home *** CD-ROM | disk | FTP | other *** search
/ Freelog 115 / FreelogNo115-MaiJuin2013.iso / Internet / AvantBrowser / asetup.exe / _data / webkit / resources.pak / Unnamed File 000117.unknown < prev    next >
Text File  |  2013-04-03  |  149KB  |  4,675 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7. WebInspector.MemoryStatistics = function(timelinePanel, model, sidebarWidth)
  8. {
  9. this._timelinePanel = timelinePanel;
  10. this._counters = [];
  11.  
  12. model.addEventListener(WebInspector.TimelineModel.Events.RecordAdded, this._onRecordAdded, this);
  13. model.addEventListener(WebInspector.TimelineModel.Events.RecordsCleared, this._onRecordsCleared, this);
  14.  
  15. this._containerAnchor = timelinePanel.element.lastChild;
  16. this._memorySidebarView = new WebInspector.SidebarView(WebInspector.SidebarView.SidebarPosition.Left, undefined, sidebarWidth);
  17. this._memorySidebarView.sidebarElement.addStyleClass("sidebar");
  18. this._memorySidebarView.element.id = "memory-graphs-container";
  19.  
  20. this._memorySidebarView.addEventListener(WebInspector.SidebarView.EventTypes.Resized, this._sidebarResized.bind(this));
  21.  
  22. this._canvasContainer = this._memorySidebarView.mainElement;
  23. this._canvasContainer.id = "memory-graphs-canvas-container";
  24. this._currentValuesBar = this._canvasContainer.createChild("div");
  25. this._currentValuesBar.id = "counter-values-bar";
  26. this._canvas = this._canvasContainer.createChild("canvas");
  27. this._canvas.id = "memory-counters-graph";
  28. this._lastMarkerXPosition = 0;
  29.  
  30. this._canvas.addEventListener("mouseover", this._onMouseOver.bind(this), true);
  31. this._canvas.addEventListener("mousemove", this._onMouseMove.bind(this), true);
  32. this._canvas.addEventListener("mouseout", this._onMouseOut.bind(this), true);
  33. this._canvas.addEventListener("click", this._onClick.bind(this), true);
  34.  
  35. this._timelineGrid = new WebInspector.TimelineGrid();
  36. this._canvasContainer.appendChild(this._timelineGrid.dividersElement);
  37.  
  38.  
  39. this._memorySidebarView.sidebarElement.createChild("div", "sidebar-tree sidebar-tree-section").textContent = WebInspector.UIString("COUNTERS");
  40. function getDocumentCount(entry)
  41. {
  42. return entry.documentCount;
  43. }
  44. function getNodeCount(entry)
  45. {
  46. return entry.nodeCount;
  47. }
  48. function getListenerCount(entry)
  49. {
  50. return entry.listenerCount;
  51. }
  52. this._counterUI = [
  53. new WebInspector.CounterUI(this, "Document Count", "Documents: %d", [100,0,0], getDocumentCount),
  54. new WebInspector.CounterUI(this, "DOM Node Count", "Nodes: %d", [0,100,0], getNodeCount),
  55. new WebInspector.CounterUI(this, "Event Listener Count", "Listeners: %d", [0,0,100], getListenerCount)
  56. ];
  57.  
  58. TimelineAgent.setIncludeMemoryDetails(true);
  59. }
  60.  
  61.  
  62. WebInspector.SwatchCheckbox = function(title, color)
  63. {
  64. this.element = document.createElement("div");
  65. this._swatch = this.element.createChild("div", "swatch");
  66. this.element.createChild("span", "title").textContent = title;
  67. this._color = color;
  68. this.checked = true;
  69.  
  70. this.element.addEventListener("click", this._toggleCheckbox.bind(this), true);
  71. }
  72.  
  73. WebInspector.SwatchCheckbox.Events = {
  74. Changed: "Changed"
  75. }
  76.  
  77. WebInspector.SwatchCheckbox.prototype = {
  78. get checked()
  79. {
  80. return this._checked;
  81. },
  82.  
  83. set checked(v)
  84. {
  85. this._checked = v;
  86. if (this._checked)
  87. this._swatch.style.backgroundColor = this._color;
  88. else
  89. this._swatch.style.backgroundColor = "";
  90. },
  91.  
  92. _toggleCheckbox: function(event)
  93. {
  94. this.checked = !this.checked;
  95. this.dispatchEventToListeners(WebInspector.SwatchCheckbox.Events.Changed);
  96. },
  97.  
  98. __proto__: WebInspector.Object.prototype
  99. }
  100.  
  101.  
  102. WebInspector.CounterUI = function(memoryCountersPane, title, currentValueLabel, rgb, valueGetter)
  103. {
  104. this._memoryCountersPane = memoryCountersPane;
  105. this.valueGetter = valueGetter;
  106. var container = memoryCountersPane._memorySidebarView.sidebarElement.createChild("div", "memory-counter-sidebar-info");
  107. var swatchColor = "rgb(" + rgb.join(",") + ")";
  108. this._swatch = new WebInspector.SwatchCheckbox(WebInspector.UIString(title), swatchColor);
  109. this._swatch.addEventListener(WebInspector.SwatchCheckbox.Events.Changed, this._toggleCounterGraph.bind(this));
  110. container.appendChild(this._swatch.element);
  111. this._range = this._swatch.element.createChild("span");
  112.  
  113. this._value = memoryCountersPane._currentValuesBar.createChild("span", "memory-counter-value");
  114. this._value.style.color = swatchColor;
  115. this._currentValueLabel = currentValueLabel;
  116.  
  117. this.graphColor = "rgba(" + rgb.join(",") + ",0.8)";
  118. this.graphYValues = [];
  119. }
  120.  
  121. WebInspector.CounterUI.prototype = {
  122. _toggleCounterGraph: function(event)
  123. {
  124. if (this._swatch.checked)
  125. this._value.removeStyleClass("hidden");
  126. else
  127. this._value.addStyleClass("hidden");
  128. this._memoryCountersPane.refresh();
  129. },
  130.  
  131. setRange: function(minValue, maxValue)
  132. {
  133. this._range.textContent = WebInspector.UIString("[ %d - %d ]", minValue, maxValue);
  134. },
  135.  
  136. updateCurrentValue: function(countersEntry)
  137. {
  138. this._value.textContent =  WebInspector.UIString(this._currentValueLabel, this.valueGetter(countersEntry));
  139. },
  140.  
  141. clearCurrentValueAndMarker: function(ctx)
  142. {
  143. this._value.textContent = "";
  144. this.restoreImageUnderMarker(ctx);
  145. },
  146.  
  147. get visible()
  148. {
  149. return this._swatch.checked;
  150. },
  151.  
  152. saveImageUnderMarker: function(ctx, x, y, radius)
  153. {
  154. const w = radius + 1;
  155. var imageData = ctx.getImageData(x - w, y - w, 2 * w, 2 * w);
  156. this._imageUnderMarker = {
  157. x: x - w,
  158. y: y - w,
  159. imageData: imageData };
  160. },
  161.  
  162. restoreImageUnderMarker: function(ctx)
  163. {
  164. if (!this.visible)
  165. return;
  166. if (this._imageUnderMarker)
  167. ctx.putImageData(this._imageUnderMarker.imageData, this._imageUnderMarker.x, this._imageUnderMarker.y);
  168. this.discardImageUnderMarker();
  169. },
  170.  
  171. discardImageUnderMarker: function()
  172. {
  173. delete this._imageUnderMarker;
  174. }
  175. }
  176.  
  177.  
  178. WebInspector.MemoryStatistics.prototype = {
  179. _onRecordsCleared: function()
  180. {
  181. this._counters = [];
  182. },
  183.  
  184. setMainTimelineGrid: function(timelineGrid)
  185. {
  186. this._mainTimelineGrid = timelineGrid;
  187. },
  188.  
  189. setTopPosition: function(top)
  190. {
  191. this._memorySidebarView.element.style.top = top + "px";
  192. this._updateSize();
  193. },
  194.  
  195. setSidebarWidth: function(width)
  196. {
  197. if (this._ignoreSidebarResize)
  198. return;
  199. this._ignoreSidebarResize = true;
  200. this._memorySidebarView.setSidebarWidth(width);
  201. this._ignoreSidebarResize = false;
  202. },
  203.  
  204. _sidebarResized: function(event)
  205. {
  206. if (this._ignoreSidebarResize)
  207. return;
  208. this._ignoreSidebarResize = true;
  209. this._timelinePanel.splitView.setSidebarWidth(event.data);
  210. this._ignoreSidebarResize = false;
  211. },
  212.  
  213. _updateSize: function()
  214. {
  215. var width = this._mainTimelineGrid.dividersElement.offsetWidth + 1;
  216. this._canvasContainer.style.width = width + "px";
  217.  
  218. var height = this._canvasContainer.offsetHeight - this._currentValuesBar.offsetHeight;
  219. this._canvas.width = width;
  220. this._canvas.height = height;
  221. },
  222.  
  223. _onRecordAdded: function(event)
  224. {
  225. var statistics = this._counters;
  226. function addStatistics(record)
  227. {
  228. var counters = record["counters"];
  229. if (!counters)
  230. return;
  231. statistics.push({
  232. time: record.endTime || record.startTime,
  233. documentCount: counters["documents"],
  234. nodeCount: counters["nodes"],
  235. listenerCount: counters["jsEventListeners"]
  236. });
  237. }
  238. WebInspector.TimelinePresentationModel.forAllRecords([event.data], null, addStatistics);
  239. },
  240.  
  241. _draw: function()
  242. {
  243. this._calculateVisibleIndexes();
  244. this._calculateXValues();
  245. this._clear();
  246.  
  247. this._setVerticalClip(10, this._canvas.height - 20);
  248. for (var i = 0; i < this._counterUI.length; i++)
  249. this._drawGraph(this._counterUI[i]);
  250. },
  251.  
  252. _calculateVisibleIndexes: function()
  253. {
  254. var calculator = this._timelinePanel.calculator;
  255. var start = calculator.minimumBoundary() * 1000;
  256. var end = calculator.maximumBoundary() * 1000;
  257. var firstIndex = 0;
  258. var lastIndex = this._counters.length - 1;
  259. for (var i = 0; i < this._counters.length; i++) {
  260. var time = this._counters[i].time;
  261. if (time <= start) {
  262. firstIndex = i;
  263. } else {
  264. if (end < time)
  265. break;
  266. lastIndex = i;
  267. }
  268. }
  269.  
  270. this._minimumIndex = firstIndex;
  271.  
  272.  
  273. this._maximumIndex = lastIndex;
  274.  
  275.  
  276. this._minTime = start;
  277. this._maxTime = end;
  278. },
  279.  
  280. _onClick: function(event)
  281. {
  282. var x = event.x - event.target.offsetParent.offsetLeft;
  283. var i = this._recordIndexAt(x);
  284. var counter = this._counters[i];
  285. if (counter)
  286. this._timelinePanel.revealRecordAt(counter.time / 1000);
  287. },
  288.  
  289. _onMouseOut: function(event)
  290. {
  291. delete this._markerXPosition;
  292.  
  293. var ctx = this._canvas.getContext("2d");
  294. for (var i = 0; i < this._counterUI.length; i++)
  295. this._counterUI[i].clearCurrentValueAndMarker(ctx);
  296. },
  297.  
  298. _onMouseOver: function(event)
  299. {
  300. this._onMouseMove(event);
  301. },
  302.  
  303. _onMouseMove: function(event)
  304. {
  305. var x = event.x - event.target.offsetParent.offsetLeft
  306. this._markerXPosition = x;
  307. this._refreshCurrentValues();
  308. },
  309.  
  310. _refreshCurrentValues: function()
  311. {
  312. if (!this._counters.length)
  313. return;
  314. if (this._markerXPosition === undefined)
  315. return;
  316. var i = this._recordIndexAt(this._markerXPosition);
  317.  
  318. for (var j = 0; j < this._counterUI.length; j++)
  319. this._counterUI[j].updateCurrentValue(this._counters[i]);
  320.  
  321. this._highlightCurrentPositionOnGraphs(this._markerXPosition, i);
  322. },
  323.  
  324. _recordIndexAt: function(x)
  325. {
  326. var i;
  327. for (i = this._minimumIndex + 1; i <= this._maximumIndex; i++) {
  328. var statX = this._counters[i].x;
  329. if (x < statX)
  330. break;
  331. }
  332. i--;
  333. return i;
  334. },
  335.  
  336. _highlightCurrentPositionOnGraphs: function(x, index)
  337. {
  338. var ctx = this._canvas.getContext("2d");
  339. for (var i = 0; i < this._counterUI.length; i++) {
  340. var counterUI = this._counterUI[i];
  341. if (!counterUI.visible)
  342. continue;
  343. counterUI.restoreImageUnderMarker(ctx);
  344. }
  345.  
  346. const radius = 2;
  347. for (var i = 0; i < this._counterUI.length; i++) {
  348. var counterUI = this._counterUI[i];
  349. if (!counterUI.visible)
  350. continue;
  351. var y = counterUI.graphYValues[index];
  352. counterUI.saveImageUnderMarker(ctx, x, y, radius);
  353. }
  354.  
  355. for (var i = 0; i < this._counterUI.length; i++) {
  356. var counterUI = this._counterUI[i];
  357. if (!counterUI.visible)
  358. continue;
  359. var y = counterUI.graphYValues[index];
  360. ctx.beginPath();
  361. ctx.arc(x, y, radius, 0, Math.PI*2, true);
  362. ctx.lineWidth = 1;
  363. ctx.fillStyle = counterUI.graphColor;
  364. ctx.strokeStyle = counterUI.graphColor;
  365. ctx.fill();
  366. ctx.stroke();
  367. ctx.closePath();
  368. }
  369. },
  370.  
  371. visible: function()
  372. {
  373. return this._memorySidebarView.isShowing();
  374. },
  375.  
  376. show: function()
  377. {
  378. var anchor =   (this._containerAnchor.nextSibling);
  379. this._memorySidebarView.show(this._timelinePanel.element, anchor);
  380. this._updateSize();
  381. this._refreshDividers();
  382. setTimeout(this._draw.bind(this), 0);
  383. },
  384.  
  385. refresh: function()
  386. {
  387. this._updateSize();
  388. this._refreshDividers();
  389. this._draw();
  390. this._refreshCurrentValues();
  391. },
  392.  
  393. hide: function()
  394. {
  395. this._memorySidebarView.detach();
  396. },
  397.  
  398. _refreshDividers: function()
  399. {
  400. this._timelineGrid.updateDividers(this._timelinePanel.calculator);
  401. },
  402.  
  403. _setVerticalClip: function(originY, height)
  404. {
  405. this._originY = originY;
  406. this._clippedHeight = height;
  407. },
  408.  
  409. _calculateXValues: function()
  410. {
  411. if (!this._counters.length)
  412. return;
  413.  
  414. var width = this._canvas.width;
  415. var xFactor = width / (this._maxTime - this._minTime);
  416.  
  417. this._counters[this._minimumIndex].x = 0;
  418. for (var i = this._minimumIndex + 1; i < this._maximumIndex; i++)
  419. this._counters[i].x = xFactor * (this._counters[i].time - this._minTime);
  420. this._counters[this._maximumIndex].x = width;
  421. },
  422.  
  423. _drawGraph: function(counterUI)
  424. {
  425. var canvas = this._canvas;
  426. var ctx = canvas.getContext("2d");
  427. var width = canvas.width;
  428. var height = this._clippedHeight;
  429. var originY = this._originY;
  430. var valueGetter = counterUI.valueGetter;
  431.  
  432. if (!this._counters.length)
  433. return;
  434.  
  435. var maxValue;
  436. var minValue;
  437. for (var i = this._minimumIndex; i <= this._maximumIndex; i++) {
  438. var value = valueGetter(this._counters[i]);
  439. if (minValue === undefined || value < minValue)
  440. minValue = value;
  441. if (maxValue === undefined || value > maxValue)
  442. maxValue = value;
  443. }
  444.  
  445. counterUI.setRange(minValue, maxValue);
  446.  
  447. if (!counterUI.visible)
  448. return;
  449.  
  450. var yValues = counterUI.graphYValues;
  451. yValues.length = this._counters.length;
  452.  
  453. var maxYRange = maxValue - minValue;
  454. var yFactor = maxYRange ? height / (maxYRange) : 1;
  455.  
  456. ctx.beginPath();
  457. var currentY = originY + (height - (valueGetter(this._counters[this._minimumIndex])- minValue) * yFactor);
  458. ctx.moveTo(0, currentY);
  459. for (var i = this._minimumIndex; i <= this._maximumIndex; i++) {
  460. var x = this._counters[i].x;
  461. ctx.lineTo(x, currentY);
  462. currentY = originY + (height - (valueGetter(this._counters[i])- minValue) * yFactor);
  463. ctx.lineTo(x, currentY);
  464.  
  465. yValues[i] = currentY;
  466. }
  467. ctx.lineTo(width, currentY);
  468. ctx.lineWidth = 1;
  469. ctx.strokeStyle = counterUI.graphColor;
  470. ctx.stroke();
  471. ctx.closePath();
  472. },
  473.  
  474. _clear: function() {
  475. var ctx = this._canvas.getContext("2d");
  476. ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  477. for (var i = 0; i < this._counterUI.length; i++)
  478. this._counterUI[i].discardImageUnderMarker();
  479. }
  480. }
  481.  
  482. ;
  483.  
  484.  
  485.  
  486. WebInspector.TimelineModel = function()
  487. {
  488. this._records = [];
  489. this._stringPool = new StringPool();
  490. this._minimumRecordTime = -1;
  491. this._maximumRecordTime = -1;
  492. this._collectionEnabled = false;
  493.  
  494. WebInspector.timelineManager.addEventListener(WebInspector.TimelineManager.EventTypes.TimelineEventRecorded, this._onRecordAdded, this);
  495. }
  496.  
  497. WebInspector.TimelineModel.TransferChunkLengthBytes = 5000000;
  498.  
  499. WebInspector.TimelineModel.RecordType = {
  500. Root: "Root",
  501. Program: "Program",
  502. EventDispatch: "EventDispatch",
  503.  
  504. BeginFrame: "BeginFrame",
  505. ScheduleStyleRecalculation: "ScheduleStyleRecalculation",
  506. RecalculateStyles: "RecalculateStyles",
  507. InvalidateLayout: "InvalidateLayout",
  508. Layout: "Layout",
  509. Paint: "Paint",
  510. ScrollLayer: "ScrollLayer",
  511. DecodeImage: "DecodeImage",
  512. ResizeImage: "ResizeImage",
  513. CompositeLayers: "CompositeLayers",
  514.  
  515. ParseHTML: "ParseHTML",
  516.  
  517. TimerInstall: "TimerInstall",
  518. TimerRemove: "TimerRemove",
  519. TimerFire: "TimerFire",
  520.  
  521. XHRReadyStateChange: "XHRReadyStateChange",
  522. XHRLoad: "XHRLoad",
  523. EvaluateScript: "EvaluateScript",
  524.  
  525. MarkLoad: "MarkLoad",
  526. MarkDOMContent: "MarkDOMContent",
  527.  
  528. TimeStamp: "TimeStamp",
  529. Time: "Time",
  530. TimeEnd: "TimeEnd",
  531.  
  532. ScheduleResourceRequest: "ScheduleResourceRequest",
  533. ResourceSendRequest: "ResourceSendRequest",
  534. ResourceReceiveResponse: "ResourceReceiveResponse",
  535. ResourceReceivedData: "ResourceReceivedData",
  536. ResourceFinish: "ResourceFinish",
  537.  
  538. FunctionCall: "FunctionCall",
  539. GCEvent: "GCEvent",
  540.  
  541. RequestAnimationFrame: "RequestAnimationFrame",
  542. CancelAnimationFrame: "CancelAnimationFrame",
  543. FireAnimationFrame: "FireAnimationFrame"
  544. }
  545.  
  546. WebInspector.TimelineModel.Events = {
  547. RecordAdded: "RecordAdded",
  548. RecordsCleared: "RecordsCleared"
  549. }
  550.  
  551. WebInspector.TimelineModel.startTimeInSeconds = function(record)
  552. {
  553. return record.startTime / 1000;
  554. }
  555.  
  556. WebInspector.TimelineModel.endTimeInSeconds = function(record)
  557. {
  558. return (typeof record.endTime === "undefined" ? record.startTime : record.endTime) / 1000;
  559. }
  560.  
  561. WebInspector.TimelineModel.durationInSeconds = function(record)
  562. {
  563. return WebInspector.TimelineModel.endTimeInSeconds(record) - WebInspector.TimelineModel.startTimeInSeconds(record);
  564. }
  565.  
  566.  
  567. WebInspector.TimelineModel.aggregateTimeForRecord = function(total, rawRecord)
  568. {
  569. var childrenTime = 0;
  570. var children = rawRecord["children"] || [];
  571. for (var i = 0; i < children.length; ++i) {
  572. WebInspector.TimelineModel.aggregateTimeForRecord(total, children[i]);
  573. childrenTime += WebInspector.TimelineModel.durationInSeconds(children[i]);
  574. }
  575. var categoryName = WebInspector.TimelinePresentationModel.recordStyle(rawRecord).category.name;
  576. var ownTime = WebInspector.TimelineModel.durationInSeconds(rawRecord) - childrenTime;
  577. total[categoryName] = (total[categoryName] || 0) + ownTime;
  578. }
  579.  
  580.  
  581. WebInspector.TimelineModel.aggregateTimeByCategory = function(total, addend)
  582. {
  583. for (var category in addend)
  584. total[category] = (total[category] || 0) + addend[category];
  585. }
  586.  
  587. WebInspector.TimelineModel.prototype = {
  588. startRecord: function()
  589. {
  590. if (this._collectionEnabled)
  591. return;
  592. this.reset();
  593. WebInspector.timelineManager.start(30);
  594. this._collectionEnabled = true;
  595. },
  596.  
  597. stopRecord: function()
  598. {
  599. if (!this._collectionEnabled)
  600. return;
  601. WebInspector.timelineManager.stop();
  602. this._collectionEnabled = false;
  603. },
  604.  
  605. get records()
  606. {
  607. return this._records;
  608. },
  609.  
  610. _onRecordAdded: function(event)
  611. {
  612. if (this._collectionEnabled)
  613. this._addRecord(event.data);
  614. },
  615.  
  616. _addRecord: function(record)
  617. {
  618. this._stringPool.internObjectStrings(record);
  619. this._records.push(record);
  620. this._updateBoundaries(record);
  621. this.dispatchEventToListeners(WebInspector.TimelineModel.Events.RecordAdded, record);
  622. },
  623.  
  624.  
  625. loadFromFile: function(file, progress)
  626. {
  627. var delegate = new WebInspector.TimelineModelLoadFromFileDelegate(this, progress);
  628. var fileReader = this._createFileReader(file, delegate);
  629. var loader = new WebInspector.TimelineModelLoader(this, fileReader, progress);
  630. fileReader.start(loader);
  631. },
  632.  
  633.  
  634. loadFromURL: function(url, progress)
  635. {
  636. var delegate = new WebInspector.TimelineModelLoadFromFileDelegate(this, progress);
  637. var urlReader = new WebInspector.ChunkedXHRReader(url, delegate);
  638. var loader = new WebInspector.TimelineModelLoader(this, urlReader, progress);
  639. urlReader.start(loader);
  640. },
  641.  
  642. _createFileReader: function(file, delegate)
  643. {
  644. return new WebInspector.ChunkedFileReader(file, WebInspector.TimelineModel.TransferChunkLengthBytes, delegate);
  645. },
  646.  
  647. _createFileWriter: function(fileName, callback)
  648. {
  649. var stream = new WebInspector.FileOutputStream();
  650. stream.open(fileName, callback);
  651. },
  652.  
  653. saveToFile: function()
  654. {
  655. var now = new Date();
  656. var fileName = "TimelineRawData-" + now.toISO8601Compact() + ".json";
  657. function callback(stream)
  658. {
  659. var saver = new WebInspector.TimelineSaver(stream);
  660. saver.save(this._records, window.navigator.appVersion);
  661. }
  662. this._createFileWriter(fileName, callback.bind(this));
  663. },
  664.  
  665. reset: function()
  666. {
  667. this._records = [];
  668. this._stringPool.reset();
  669. this._minimumRecordTime = -1;
  670. this._maximumRecordTime = -1;
  671. this.dispatchEventToListeners(WebInspector.TimelineModel.Events.RecordsCleared);
  672. },
  673.  
  674. minimumRecordTime: function()
  675. {
  676. return this._minimumRecordTime;
  677. },
  678.  
  679. maximumRecordTime: function()
  680. {
  681. return this._maximumRecordTime;
  682. },
  683.  
  684. _updateBoundaries: function(record)
  685. {
  686. var startTime = WebInspector.TimelineModel.startTimeInSeconds(record);
  687. var endTime = WebInspector.TimelineModel.endTimeInSeconds(record);
  688.  
  689. if (this._minimumRecordTime === -1 || startTime < this._minimumRecordTime)
  690. this._minimumRecordTime = startTime;
  691. if (this._maximumRecordTime === -1 || endTime > this._maximumRecordTime)
  692. this._maximumRecordTime = endTime;
  693. },
  694.  
  695.  
  696. recordOffsetInSeconds: function(rawRecord)
  697. {
  698. return WebInspector.TimelineModel.startTimeInSeconds(rawRecord) - this._minimumRecordTime;
  699. },
  700.  
  701. __proto__: WebInspector.Object.prototype
  702. }
  703.  
  704.  
  705. WebInspector.TimelineModelLoader = function(model, reader, progress)
  706. {
  707. this._model = model;
  708. this._reader = reader;
  709. this._progress = progress;
  710. this._buffer = "";
  711. this._firstChunk = true;
  712. }
  713.  
  714. WebInspector.TimelineModelLoader.prototype = {
  715.  
  716. write: function(chunk)
  717. {
  718. var data = this._buffer + chunk;
  719. var lastIndex = 0;
  720. var index;
  721. do {
  722. index = lastIndex;
  723. lastIndex = WebInspector.findBalancedCurlyBrackets(data, index);
  724. } while (lastIndex !== -1)
  725.  
  726. var json = data.slice(0, index) + "]";
  727. this._buffer = data.slice(index);
  728.  
  729. if (!index)
  730. return;
  731.  
  732.  
  733. if (!this._firstChunk)
  734. json = "[0" + json;
  735.  
  736. var items;
  737. try {
  738. items =   (JSON.parse(json));
  739. } catch (e) {
  740. WebInspector.showErrorMessage("Malformed timeline data.");
  741. this._model.reset();
  742. this._reader.cancel();
  743. this._progress.done();
  744. return;
  745. }
  746.  
  747. if (this._firstChunk) {
  748. this._version = items[0];
  749. this._firstChunk = false;
  750. this._model.reset();
  751. }
  752.  
  753.  
  754. for (var i = 1, size = items.length; i < size; ++i)
  755. this._model._addRecord(items[i]);
  756. },
  757.  
  758. close: function() { }
  759. }
  760.  
  761.  
  762. WebInspector.TimelineModelLoadFromFileDelegate = function(model, progress)
  763. {
  764. this._model = model;
  765. this._progress = progress;
  766. }
  767.  
  768. WebInspector.TimelineModelLoadFromFileDelegate.prototype = {
  769. onTransferStarted: function()
  770. {
  771. this._progress.setTitle(WebInspector.UIString("Loading\u2026"));
  772. },
  773.  
  774.  
  775. onChunkTransferred: function(reader)
  776. {
  777. if (this._progress.isCanceled()) {
  778. reader.cancel();
  779. this._progress.done();
  780. this._model.reset();
  781. return;
  782. }
  783.  
  784. var totalSize = reader.fileSize();
  785. if (totalSize) {
  786. this._progress.setTotalWork(totalSize);
  787. this._progress.setWorked(reader.loadedSize());
  788. }
  789. },
  790.  
  791. onTransferFinished: function()
  792. {
  793. this._progress.done();
  794. },
  795.  
  796.  
  797. onError: function(reader, event)
  798. {
  799. this._progress.done();
  800. this._model.reset();
  801. switch (event.target.error.code) {
  802. case FileError.NOT_FOUND_ERR:
  803. WebInspector.showErrorMessage(WebInspector.UIString("File \"%s\" not found.", reader.fileName()));
  804. break;
  805. case FileError.NOT_READABLE_ERR:
  806. WebInspector.showErrorMessage(WebInspector.UIString("File \"%s\" is not readable", reader.fileName()));
  807. break;
  808. case FileError.ABORT_ERR:
  809. break;
  810. default:
  811. WebInspector.showErrorMessage(WebInspector.UIString("An error occurred while reading the file \"%s\"", reader.fileName()));
  812. }
  813. }
  814. }
  815.  
  816.  
  817. WebInspector.TimelineSaver = function(stream)
  818. {
  819. this._stream = stream;
  820. }
  821.  
  822. WebInspector.TimelineSaver.prototype = {
  823.  
  824. save: function(records, version)
  825. {
  826. this._records = records;
  827. this._recordIndex = 0;
  828. this._prologue = "[" + JSON.stringify(version);
  829.  
  830. this._writeNextChunk(this._stream);
  831. },
  832.  
  833. _writeNextChunk: function(stream)
  834. {
  835. const separator = ",\n";
  836. var data = [];
  837. var length = 0;
  838.  
  839. if (this._prologue) {
  840. data.push(this._prologue);
  841. length += this._prologue.length;
  842. delete this._prologue;
  843. } else {
  844. if (this._recordIndex === this._records.length) {
  845. stream.close();
  846. return;
  847. }
  848. data.push("");
  849. }
  850. while (this._recordIndex < this._records.length) {
  851. var item = JSON.stringify(this._records[this._recordIndex]);
  852. var itemLength = item.length + separator.length;
  853. if (length + itemLength > WebInspector.TimelineModel.TransferChunkLengthBytes)
  854. break;
  855. length += itemLength;
  856. data.push(item);
  857. ++this._recordIndex;
  858. }
  859. if (this._recordIndex === this._records.length)
  860. data.push(data.pop() + "]");
  861. stream.write(data.join(separator), this._writeNextChunk.bind(this));
  862. }
  863. }
  864. ;
  865.  
  866.  
  867.  
  868. WebInspector.TimelineOverviewPane = function(model)
  869. {
  870. WebInspector.View.call(this);
  871. this.element.id = "timeline-overview-panel";
  872.  
  873. this._windowStartTime = 0;
  874. this._windowEndTime = Infinity;
  875. this._eventDividers = [];
  876.  
  877. this._model = model;
  878.  
  879. this._topPaneSidebarElement = document.createElement("div");
  880. this._topPaneSidebarElement.id = "timeline-overview-sidebar";
  881.  
  882. var overviewTreeElement = document.createElement("ol");
  883. overviewTreeElement.className = "sidebar-tree";
  884. this._topPaneSidebarElement.appendChild(overviewTreeElement);
  885. this.element.appendChild(this._topPaneSidebarElement);
  886.  
  887. var topPaneSidebarTree = new TreeOutline(overviewTreeElement);
  888.  
  889. this._currentMode = WebInspector.TimelineOverviewPane.Mode.Events;
  890.  
  891. this._overviewItems = {};
  892. this._overviewItems[WebInspector.TimelineOverviewPane.Mode.Events] = new WebInspector.SidebarTreeElement("timeline-overview-sidebar-events",
  893. WebInspector.UIString("Events"));
  894. if (Capabilities.timelineSupportsFrameInstrumentation) {
  895. this._overviewItems[WebInspector.TimelineOverviewPane.Mode.Frames] = new WebInspector.SidebarTreeElement("timeline-overview-sidebar-frames",
  896. WebInspector.UIString("Frames"));
  897. }
  898. this._overviewItems[WebInspector.TimelineOverviewPane.Mode.Memory] = new WebInspector.SidebarTreeElement("timeline-overview-sidebar-memory",
  899. WebInspector.UIString("Memory"));
  900.  
  901. for (var mode in this._overviewItems) {
  902. var item = this._overviewItems[mode];
  903. item.onselect = this.setMode.bind(this, mode);
  904. topPaneSidebarTree.appendChild(item);
  905. }
  906.  
  907. this._overviewItems[this._currentMode].revealAndSelect(false);
  908.  
  909. this._overviewContainer = this.element.createChild("div", "fill");
  910. this._overviewContainer.id = "timeline-overview-container";
  911.  
  912. this._overviewGrid = new WebInspector.TimelineGrid();
  913. this._overviewGrid.element.id = "timeline-overview-grid";
  914. this._overviewGrid.itemsGraphsElement.id = "timeline-overview-timelines";
  915.  
  916. this._overviewContainer.appendChild(this._overviewGrid.element);
  917.  
  918. this._heapGraph = new WebInspector.HeapGraph(this._model);
  919. this._heapGraph.element.id = "timeline-overview-memory";
  920. this._overviewGrid.element.insertBefore(this._heapGraph.element, this._overviewGrid.itemsGraphsElement);
  921.  
  922. this._overviewWindow = new WebInspector.TimelineOverviewWindow(this._overviewContainer, this._overviewGrid.dividersLabelBarElement);
  923. this._overviewWindow.addEventListener(WebInspector.TimelineOverviewWindow.Events.WindowChanged, this._onWindowChanged, this);
  924.  
  925. var separatorElement = document.createElement("div");
  926. separatorElement.id = "timeline-overview-separator";
  927. this.element.appendChild(separatorElement);
  928.  
  929. this._categoryStrips = new WebInspector.TimelineCategoryStrips(this._model);
  930. this._overviewGrid.itemsGraphsElement.appendChild(this._categoryStrips.element);
  931.  
  932. var categories = WebInspector.TimelinePresentationModel.categories();
  933. for (var category in categories)
  934. categories[category].addEventListener(WebInspector.TimelineCategory.Events.VisibilityChanged, this._onCategoryVisibilityChanged, this);
  935.  
  936. this._overviewGrid.setScrollAndDividerTop(0, 0);
  937. this._overviewCalculator = new WebInspector.TimelineOverviewCalculator();
  938.  
  939. model.addEventListener(WebInspector.TimelineModel.Events.RecordAdded, this._onRecordAdded, this);
  940. model.addEventListener(WebInspector.TimelineModel.Events.RecordsCleared, this._reset, this);
  941. }
  942.  
  943. WebInspector.TimelineOverviewPane.MinSelectableSize = 12;
  944.  
  945. WebInspector.TimelineOverviewPane.WindowScrollSpeedFactor = .3;
  946.  
  947. WebInspector.TimelineOverviewPane.ResizerOffset = 3.5; 
  948.  
  949. WebInspector.TimelineOverviewPane.Mode = {
  950. Events: "Events",
  951. Frames: "Frames",
  952. Memory: "Memory"
  953. };
  954.  
  955. WebInspector.TimelineOverviewPane.Events = {
  956. ModeChanged: "ModeChanged",
  957. WindowChanged: "WindowChanged"
  958. };
  959.  
  960. WebInspector.TimelineOverviewPane.prototype = {
  961. wasShown: function()
  962. {
  963. this._update();
  964. },
  965.  
  966. onResize: function()
  967. {
  968. this._update();
  969. },
  970.  
  971. setMode: function(newMode)
  972. {
  973. if (this._currentMode === newMode)
  974. return;
  975.  
  976. this._currentMode = newMode;
  977. this._setFrameMode(this._currentMode === WebInspector.TimelineOverviewPane.Mode.Frames);
  978. switch (this._currentMode) {
  979. case WebInspector.TimelineOverviewPane.Mode.Events:
  980. case WebInspector.TimelineOverviewPane.Mode.Frames:
  981. this._heapGraph.hide();
  982. this._overviewGrid.itemsGraphsElement.removeStyleClass("hidden");
  983. break;
  984. case WebInspector.TimelineOverviewPane.Mode.Memory:
  985. this._overviewGrid.itemsGraphsElement.addStyleClass("hidden");
  986. this._heapGraph.show();
  987. }
  988. this._overviewItems[this._currentMode].revealAndSelect(false);
  989. this.dispatchEventToListeners(WebInspector.TimelineOverviewPane.Events.ModeChanged, this._currentMode);
  990. this._update();
  991. },
  992.  
  993. _setFrameMode: function(enabled)
  994. {
  995. if (!enabled === !this._frameOverview)
  996. return;
  997. if (enabled) {
  998. this._frameOverview = new WebInspector.TimelineFrameOverview(this._model);
  999. this._frameOverview.show(this._overviewContainer);
  1000. } else {
  1001. this._frameOverview.detach();
  1002. this._frameOverview = null;
  1003. this._overviewGrid.itemsGraphsElement.removeStyleClass("hidden");
  1004. this._categoryStrips.update();
  1005. }
  1006. },
  1007.  
  1008. _onCategoryVisibilityChanged: function(event)
  1009. {
  1010. if (this._currentMode === WebInspector.TimelineOverviewPane.Mode.Events)
  1011. this._categoryStrips.update();
  1012. },
  1013.  
  1014. _update: function()
  1015. {
  1016. delete this._refreshTimeout;
  1017.  
  1018. this._updateWindow();
  1019. this._overviewCalculator.setWindow(this._model.minimumRecordTime(), this._model.maximumRecordTime());
  1020. this._overviewCalculator.setDisplayWindow(0, this._overviewContainer.clientWidth);
  1021.  
  1022. if (this._heapGraph.visible)
  1023. this._heapGraph.update();
  1024. else if (this._frameOverview)
  1025. this._frameOverview.update();
  1026. else
  1027. this._categoryStrips.update();
  1028.  
  1029. this._overviewGrid.updateDividers(this._overviewCalculator);
  1030. this._updateEventDividers();
  1031. },
  1032.  
  1033. _updateEventDividers: function()
  1034. {
  1035. var records = this._eventDividers;
  1036. this._overviewGrid.removeEventDividers();
  1037. var dividers = [];
  1038. for (var i = 0; i < records.length; ++i) {
  1039. var record = records[i];
  1040. var positions = this._overviewCalculator.computeBarGraphPercentages(record);
  1041. var dividerPosition = Math.round(positions.start * 10);
  1042. if (dividers[dividerPosition])
  1043. continue;
  1044. var divider = WebInspector.TimelinePresentationModel.createEventDivider(record.type);
  1045. divider.style.left = positions.start + "%";
  1046. dividers[dividerPosition] = divider;
  1047. }
  1048. this._overviewGrid.addEventDividers(dividers);
  1049. },
  1050.  
  1051.  
  1052. sidebarResized: function(width)
  1053. {
  1054. this._overviewContainer.style.left = width + "px";
  1055. this._topPaneSidebarElement.style.width = width + "px";
  1056. this._update();
  1057. },
  1058.  
  1059.  
  1060. addFrame: function(frame)
  1061. {
  1062. this._frameOverview.addFrame(frame);
  1063. this._scheduleRefresh();
  1064. },
  1065.  
  1066.  
  1067. zoomToFrame: function(frame)
  1068. {
  1069. var window = this._frameOverview.framePosition(frame);
  1070. if (!window)
  1071. return;
  1072.  
  1073. this._overviewWindow._setWindowPosition(window.start, window.end);
  1074. },
  1075.  
  1076. _onRecordAdded: function(event)
  1077. {
  1078. var record = event.data;
  1079. var eventDividers = this._eventDividers;
  1080. function addEventDividers(record)
  1081. {
  1082. if (WebInspector.TimelinePresentationModel.isEventDivider(record))
  1083. eventDividers.push(record);
  1084. }
  1085. WebInspector.TimelinePresentationModel.forAllRecords([record], addEventDividers);
  1086. this._scheduleRefresh();
  1087. },
  1088.  
  1089. _reset: function()
  1090. {
  1091. this._windowStartTime = 0;
  1092. this._windowEndTime = Infinity;
  1093. this._overviewWindow.reset();
  1094. this._overviewCalculator.reset();
  1095. this._eventDividers = [];
  1096. this._overviewGrid.updateDividers(this._overviewCalculator);
  1097. if (this._frameOverview)
  1098. this._frameOverview.reset();
  1099. this._update();
  1100. },
  1101.  
  1102. windowStartTime: function()
  1103. {
  1104. return this._windowStartTime || this._model.minimumRecordTime();
  1105. },
  1106.  
  1107. windowEndTime: function()
  1108. {
  1109. return this._windowEndTime < Infinity ? this._windowEndTime : this._model.maximumRecordTime();
  1110. },
  1111.  
  1112. windowLeft: function()
  1113. {
  1114. return this._overviewWindow.windowLeft;
  1115. },
  1116.  
  1117. windowRight: function()
  1118. {
  1119. return this._overviewWindow.windowRight;
  1120. },
  1121.  
  1122. _onWindowChanged: function()
  1123. {
  1124. if (this._ignoreWindowChangedEvent)
  1125. return;
  1126. if (this._frameOverview) {
  1127. var times = this._frameOverview.getWindowTimes(this.windowLeft(), this.windowRight());
  1128. this._windowStartTime = times.startTime;
  1129. this._windowEndTime = times.endTime;
  1130. } else {
  1131. var absoluteMin = this._model.minimumRecordTime();
  1132. var absoluteMax = this._model.maximumRecordTime();
  1133. this._windowStartTime = absoluteMin + (absoluteMax - absoluteMin) * this.windowLeft();
  1134. this._windowEndTime = absoluteMin + (absoluteMax - absoluteMin) * this.windowRight();
  1135. }
  1136. this.dispatchEventToListeners(WebInspector.TimelineOverviewPane.Events.WindowChanged);
  1137. },
  1138.  
  1139.  
  1140. setWindowTimes: function(left, right)
  1141. {
  1142. this._windowStartTime = left;
  1143. this._windowEndTime = right;
  1144. this._updateWindow();
  1145. },
  1146.  
  1147. _updateWindow: function()
  1148. {
  1149. var offset = this._model.minimumRecordTime();
  1150. var timeSpan = this._model.maximumRecordTime() - offset;
  1151. var left = this._windowStartTime ? (this._windowStartTime - offset) / timeSpan : 0;
  1152. var right = this._windowEndTime < Infinity ? (this._windowEndTime - offset) / timeSpan : 1;
  1153. this._ignoreWindowChangedEvent = true;
  1154. this._overviewWindow._setWindow(left, right);
  1155. this._ignoreWindowChangedEvent = false;
  1156. },
  1157.  
  1158.  
  1159. setShowShortEvents: function(value)
  1160. {
  1161. this._categoryStrips.setShowShortEvents(value);
  1162. },
  1163.  
  1164. _scheduleRefresh: function()
  1165. {
  1166. if (this._refreshTimeout)
  1167. return;
  1168. if (!this.isShowing())
  1169. return;
  1170. this._refreshTimeout = setTimeout(this._update.bind(this), 300);
  1171. },
  1172.  
  1173. __proto__: WebInspector.View.prototype
  1174. }
  1175.  
  1176.  
  1177. WebInspector.TimelineOverviewWindow = function(parentElement, dividersLabelBarElement)
  1178. {
  1179. this._parentElement = parentElement;
  1180. this._dividersLabelBarElement = dividersLabelBarElement;
  1181.  
  1182. WebInspector.installDragHandle(this._parentElement, this._startWindowSelectorDragging.bind(this), this._windowSelectorDragging.bind(this), this._endWindowSelectorDragging.bind(this), "ew-resize");
  1183. WebInspector.installDragHandle(this._dividersLabelBarElement, this._startWindowDragging.bind(this), this._windowDragging.bind(this), this._endWindowDragging.bind(this), "ew-resize");
  1184.  
  1185. this.windowLeft = 0.0;
  1186. this.windowRight = 1.0;
  1187.  
  1188. this._parentElement.addEventListener("mousewheel", this._onMouseWheel.bind(this), true);
  1189. this._parentElement.addEventListener("dblclick", this._resizeWindowMaximum.bind(this), true);
  1190.  
  1191. this._overviewWindowElement = document.createElement("div");
  1192. this._overviewWindowElement.className = "timeline-overview-window";
  1193. parentElement.appendChild(this._overviewWindowElement);
  1194.  
  1195. this._overviewWindowBordersElement = document.createElement("div");
  1196. this._overviewWindowBordersElement.className = "timeline-overview-window-rulers";
  1197. parentElement.appendChild(this._overviewWindowBordersElement);
  1198.  
  1199. var overviewDividersBackground = document.createElement("div");
  1200. overviewDividersBackground.className = "timeline-overview-dividers-background";
  1201. parentElement.appendChild(overviewDividersBackground);
  1202.  
  1203. this._leftResizeElement = document.createElement("div");
  1204. this._leftResizeElement.className = "timeline-window-resizer";
  1205. this._leftResizeElement.style.left = 0;
  1206. parentElement.appendChild(this._leftResizeElement);
  1207. WebInspector.installDragHandle(this._leftResizeElement, null, this._leftResizeElementDragging.bind(this), null, "ew-resize");
  1208.  
  1209. this._rightResizeElement = document.createElement("div");
  1210. this._rightResizeElement.className = "timeline-window-resizer timeline-window-resizer-right";
  1211. this._rightResizeElement.style.right = 0;
  1212. parentElement.appendChild(this._rightResizeElement);
  1213. WebInspector.installDragHandle(this._rightResizeElement, null, this._rightResizeElementDragging.bind(this), null, "ew-resize");
  1214. }
  1215.  
  1216. WebInspector.TimelineOverviewWindow.Events = {
  1217. WindowChanged: "WindowChanged"
  1218. }
  1219.  
  1220. WebInspector.TimelineOverviewWindow.prototype = {
  1221. reset: function()
  1222. {
  1223. this.windowLeft = 0.0;
  1224. this.windowRight = 1.0;
  1225.  
  1226. this._overviewWindowElement.style.left = "0%";
  1227. this._overviewWindowElement.style.width = "100%";
  1228. this._overviewWindowBordersElement.style.left = "0%";
  1229. this._overviewWindowBordersElement.style.right = "0%";
  1230. this._leftResizeElement.style.left = "0%";
  1231. this._rightResizeElement.style.left = "100%";
  1232. },
  1233.  
  1234.  
  1235. _leftResizeElementDragging: function(event)
  1236. {
  1237. this._resizeWindowLeft(event.pageX - this._parentElement.offsetLeft);
  1238. event.preventDefault();
  1239. },
  1240.  
  1241.  
  1242. _rightResizeElementDragging: function(event)
  1243. {
  1244. this._resizeWindowRight(event.pageX - this._parentElement.offsetLeft);
  1245. event.preventDefault();
  1246. },
  1247.  
  1248.  
  1249. _startWindowSelectorDragging: function(event)
  1250. {
  1251. var position = event.pageX - this._parentElement.offsetLeft;
  1252. this._overviewWindowSelector = new WebInspector.TimelineOverviewPane.WindowSelector(this._parentElement, position);
  1253. return true;
  1254. },
  1255.  
  1256.  
  1257. _windowSelectorDragging: function(event)
  1258. {
  1259. this._overviewWindowSelector._updatePosition(event.pageX - this._parentElement.offsetLeft);
  1260. event.preventDefault();
  1261. },
  1262.  
  1263.  
  1264. _endWindowSelectorDragging: function(event)
  1265. {
  1266. var window = this._overviewWindowSelector._close(event.pageX - this._parentElement.offsetLeft);
  1267. delete this._overviewWindowSelector;
  1268. if (window.end === window.start) { 
  1269. var middle = window.end;
  1270. window.start = Math.max(0, middle - WebInspector.TimelineOverviewPane.MinSelectableSize / 2);
  1271. window.end = Math.min(this._parentElement.clientWidth, middle + WebInspector.TimelineOverviewPane.MinSelectableSize / 2);
  1272. } else if (window.end - window.start < WebInspector.TimelineOverviewPane.MinSelectableSize) {
  1273. if (this._parentElement.clientWidth - window.end > WebInspector.TimelineOverviewPane.MinSelectableSize)
  1274. window.end = window.start + WebInspector.TimelineOverviewPane.MinSelectableSize;
  1275. else
  1276. window.start = window.end - WebInspector.TimelineOverviewPane.MinSelectableSize;
  1277. }
  1278. this._setWindowPosition(window.start, window.end);
  1279. },
  1280.  
  1281.  
  1282. _startWindowDragging: function(event)
  1283. {
  1284. var windowLeft = this._leftResizeElement.offsetLeft + WebInspector.TimelineOverviewPane.ResizerOffset;
  1285. this._dragOffset = windowLeft - event.pageX;
  1286. return true;
  1287. },
  1288.  
  1289.  
  1290. _windowDragging: function(event)
  1291. {
  1292. var windowLeft = this._leftResizeElement.offsetLeft + WebInspector.TimelineOverviewPane.ResizerOffset;
  1293. var start = this._dragOffset + event.pageX;
  1294. this._moveWindow(start);
  1295. event.preventDefault();
  1296. },
  1297.  
  1298.  
  1299. _endWindowDragging: function(event)
  1300. {
  1301. delete this._dragOffset;
  1302. },
  1303.  
  1304.  
  1305. _moveWindow: function(start)
  1306. {
  1307. var windowLeft = this._leftResizeElement.offsetLeft + WebInspector.TimelineOverviewPane.ResizerOffset;
  1308. var windowRight = this._rightResizeElement.offsetLeft + WebInspector.TimelineOverviewPane.ResizerOffset;
  1309. var windowSize = windowRight - windowLeft;
  1310. var end = start + windowSize;
  1311.  
  1312. if (start < 0) {
  1313. start = 0;
  1314. end = windowSize;
  1315. }
  1316.  
  1317. if (end > this._parentElement.clientWidth) {
  1318. end = this._parentElement.clientWidth;
  1319. start = end - windowSize;
  1320. }
  1321. this._setWindowPosition(start, end);
  1322. },
  1323.  
  1324.  
  1325. _resizeWindowLeft: function(start)
  1326. {
  1327.  
  1328. if (start < 10)
  1329. start = 0;
  1330. else if (start > this._rightResizeElement.offsetLeft -  4)
  1331. start = this._rightResizeElement.offsetLeft - 4;
  1332. this._setWindowPosition(start, null);
  1333. },
  1334.  
  1335.  
  1336. _resizeWindowRight: function(end)
  1337. {
  1338.  
  1339. if (end > this._parentElement.clientWidth - 10)
  1340. end = this._parentElement.clientWidth;
  1341. else if (end < this._leftResizeElement.offsetLeft + WebInspector.TimelineOverviewPane.MinSelectableSize)
  1342. end = this._leftResizeElement.offsetLeft + WebInspector.TimelineOverviewPane.MinSelectableSize;
  1343. this._setWindowPosition(null, end);
  1344. },
  1345.  
  1346. _resizeWindowMaximum: function()
  1347. {
  1348. this._setWindowPosition(0, this._parentElement.clientWidth);
  1349. },
  1350.  
  1351.  
  1352. _setWindow: function(left, right)
  1353. {
  1354. var clientWidth = this._parentElement.clientWidth;
  1355. this._setWindowPosition(left * clientWidth, right * clientWidth);
  1356. },
  1357.  
  1358.  
  1359. _setWindowPosition: function(start, end)
  1360. {
  1361. var clientWidth = this._parentElement.clientWidth;
  1362. const rulerAdjustment = 1 / clientWidth;
  1363. if (typeof start === "number") {
  1364. this.windowLeft = start / clientWidth;
  1365. this._leftResizeElement.style.left = this.windowLeft * 100 + "%";
  1366. this._overviewWindowElement.style.left = this.windowLeft * 100 + "%";
  1367. this._overviewWindowBordersElement.style.left = (this.windowLeft - rulerAdjustment) * 100 + "%";
  1368. }
  1369. if (typeof end === "number") {
  1370. this.windowRight = end / clientWidth;
  1371. this._rightResizeElement.style.left = this.windowRight * 100 + "%";
  1372. }
  1373. this._overviewWindowElement.style.width = (this.windowRight - this.windowLeft) * 100 + "%";
  1374. this._overviewWindowBordersElement.style.right = (1 - this.windowRight + 2 * rulerAdjustment) * 100 + "%";
  1375. this.dispatchEventToListeners(WebInspector.TimelineOverviewWindow.Events.WindowChanged);
  1376. },
  1377.  
  1378.  
  1379. _onMouseWheel: function(event)
  1380. {
  1381. const zoomFactor = 1.1;
  1382. const mouseWheelZoomSpeed = 1 / 120;
  1383.  
  1384. if (typeof event.wheelDeltaY === "number" && event.wheelDeltaY) {
  1385. var referencePoint = event.pageX - this._parentElement.offsetLeft;
  1386. this._zoom(Math.pow(zoomFactor, -event.wheelDeltaY * mouseWheelZoomSpeed), referencePoint);
  1387. }
  1388. if (typeof event.wheelDeltaX === "number" && event.wheelDeltaX) {
  1389. var windowLeft = this._leftResizeElement.offsetLeft + WebInspector.TimelineOverviewPane.ResizerOffset;
  1390. var start = windowLeft - Math.round(event.wheelDeltaX * WebInspector.TimelineOverviewPane.WindowScrollSpeedFactor);
  1391. this._moveWindow(start);
  1392. event.preventDefault();
  1393. }
  1394. },
  1395.  
  1396.  
  1397. _zoom: function(factor, referencePoint)
  1398. {
  1399. var left = this._leftResizeElement.offsetLeft + WebInspector.TimelineOverviewPane.ResizerOffset;
  1400. var right = this._rightResizeElement.offsetLeft + WebInspector.TimelineOverviewPane.ResizerOffset;
  1401.  
  1402. var delta = factor * (right - left);
  1403. if (factor < 1 && delta < WebInspector.TimelineOverviewPane.MinSelectableSize)
  1404. return;
  1405. var max = this._parentElement.clientWidth;
  1406. left = Math.max(0, Math.min(max - delta, referencePoint + (left - referencePoint) * factor));
  1407. right = Math.min(max, left + delta);
  1408. this._setWindowPosition(left, right);
  1409. },
  1410.  
  1411. __proto__: WebInspector.Object.prototype
  1412. }
  1413.  
  1414.  
  1415. WebInspector.TimelineOverviewCalculator = function()
  1416. {
  1417. }
  1418.  
  1419. WebInspector.TimelineOverviewCalculator.prototype = {
  1420.  
  1421. computePosition: function(time)
  1422. {
  1423. return (time - this._minimumBoundary) / this.boundarySpan() * this._workingArea + this.paddingLeft;
  1424. },
  1425.  
  1426. computeBarGraphPercentages: function(record)
  1427. {
  1428. var start = (WebInspector.TimelineModel.startTimeInSeconds(record) - this._minimumBoundary) / this.boundarySpan() * 100;
  1429. var end = (WebInspector.TimelineModel.endTimeInSeconds(record) - this._minimumBoundary) / this.boundarySpan() * 100;
  1430. return {start: start, end: end};
  1431. },
  1432.  
  1433.  
  1434. setWindow: function(minimum, maximum)
  1435. {
  1436. this._minimumBoundary = minimum >= 0 ? minimum : undefined;
  1437. this._maximumBoundary = maximum >= 0 ? maximum : undefined;
  1438. },
  1439.  
  1440.  
  1441. setDisplayWindow: function(paddingLeft, clientWidth)
  1442. {
  1443. this._workingArea = clientWidth - paddingLeft;
  1444. this.paddingLeft = paddingLeft;
  1445. },
  1446.  
  1447. reset: function()
  1448. {
  1449. this.setWindow();
  1450. },
  1451.  
  1452. formatTime: function(value)
  1453. {
  1454. return Number.secondsToString(value);
  1455. },
  1456.  
  1457. maximumBoundary: function()
  1458. {
  1459. return this._maximumBoundary;
  1460. },
  1461.  
  1462. minimumBoundary: function()
  1463. {
  1464. return this._minimumBoundary;
  1465. },
  1466.  
  1467. boundarySpan: function()
  1468. {
  1469. return this._maximumBoundary - this._minimumBoundary;
  1470. }
  1471. }
  1472.  
  1473.  
  1474. WebInspector.TimelineOverviewPane.WindowSelector = function(parent, position)
  1475. {
  1476. this._startPosition = position;
  1477. this._width = parent.offsetWidth;
  1478. this._windowSelector = document.createElement("div");
  1479. this._windowSelector.className = "timeline-window-selector";
  1480. this._windowSelector.style.left = this._startPosition + "px";
  1481. this._windowSelector.style.right = this._width - this._startPosition +  + "px";
  1482. parent.appendChild(this._windowSelector);
  1483. }
  1484.  
  1485. WebInspector.TimelineOverviewPane.WindowSelector.prototype = {
  1486. _createSelectorElement: function(parent, left, width, height)
  1487. {
  1488. var selectorElement = document.createElement("div");
  1489. selectorElement.className = "timeline-window-selector";
  1490. selectorElement.style.left = left + "px";
  1491. selectorElement.style.width = width + "px";
  1492. selectorElement.style.top = "0px";
  1493. selectorElement.style.height = height + "px";
  1494. parent.appendChild(selectorElement);
  1495. return selectorElement;
  1496. },
  1497.  
  1498. _close: function(position)
  1499. {
  1500. position = Math.max(0, Math.min(position, this._width));
  1501. this._windowSelector.parentNode.removeChild(this._windowSelector);
  1502. return this._startPosition < position ? {start: this._startPosition, end: position} : {start: position, end: this._startPosition};
  1503. },
  1504.  
  1505. _updatePosition: function(position)
  1506. {
  1507. position = Math.max(0, Math.min(position, this._width));
  1508. if (position < this._startPosition) {
  1509. this._windowSelector.style.left = position + "px";
  1510. this._windowSelector.style.right = this._width - this._startPosition + "px";
  1511. } else {
  1512. this._windowSelector.style.left = this._startPosition + "px";
  1513. this._windowSelector.style.right = this._width - position + "px";
  1514. }
  1515. }
  1516. }
  1517.  
  1518.  
  1519. WebInspector.HeapGraph = function(model)
  1520. {
  1521. this._canvas = document.createElement("canvas");
  1522. this._model = model;
  1523.  
  1524. this._maxHeapSizeLabel = document.createElement("div");
  1525. this._maxHeapSizeLabel.addStyleClass("max");
  1526. this._maxHeapSizeLabel.addStyleClass("memory-graph-label");
  1527. this._minHeapSizeLabel = document.createElement("div");
  1528. this._minHeapSizeLabel.addStyleClass("min");
  1529. this._minHeapSizeLabel.addStyleClass("memory-graph-label");
  1530.  
  1531. this._element = document.createElement("div");
  1532. this._element.addStyleClass("hidden");
  1533. this._element.appendChild(this._canvas);
  1534. this._element.appendChild(this._maxHeapSizeLabel);
  1535. this._element.appendChild(this._minHeapSizeLabel);
  1536. }
  1537.  
  1538. WebInspector.HeapGraph.prototype = {
  1539.  
  1540. get element()
  1541. {
  1542. return this._element;
  1543. },
  1544.  
  1545.  
  1546. get visible()
  1547. {
  1548. return !this.element.hasStyleClass("hidden");
  1549. },
  1550.  
  1551. show: function()
  1552. {
  1553. this.element.removeStyleClass("hidden");
  1554. },
  1555.  
  1556. hide: function()
  1557. {
  1558. this.element.addStyleClass("hidden");
  1559. },
  1560.  
  1561. update: function()
  1562. {
  1563. var records = this._model.records;
  1564. if (!records.length)
  1565. return;
  1566.  
  1567. const yPadding = 5;
  1568. this._canvas.width = this.element.clientWidth;
  1569. this._canvas.height = this.element.clientHeight - yPadding;
  1570.  
  1571. const lowerOffset = 3;
  1572. var maxUsedHeapSize = 0;
  1573. var minUsedHeapSize = 100000000000;
  1574. var minTime = this._model.minimumRecordTime();
  1575. var maxTime = this._model.maximumRecordTime();;
  1576. WebInspector.TimelinePresentationModel.forAllRecords(records, function(r) {
  1577. maxUsedHeapSize = Math.max(maxUsedHeapSize, r.usedHeapSize || maxUsedHeapSize);
  1578. minUsedHeapSize = Math.min(minUsedHeapSize, r.usedHeapSize || minUsedHeapSize);
  1579. });
  1580. minUsedHeapSize = Math.min(minUsedHeapSize, maxUsedHeapSize);
  1581.  
  1582. var width = this._canvas.width;
  1583. var height = this._canvas.height - lowerOffset;
  1584. var xFactor = width / (maxTime - minTime);
  1585. var yFactor = height / (maxUsedHeapSize - minUsedHeapSize);
  1586.  
  1587. var histogram = new Array(width);
  1588. WebInspector.TimelinePresentationModel.forAllRecords(records, function(r) {
  1589. if (!r.usedHeapSize)
  1590. return;
  1591. var x = Math.round((WebInspector.TimelineModel.endTimeInSeconds(r) - minTime) * xFactor);
  1592. var y = Math.round((r.usedHeapSize - minUsedHeapSize) * yFactor);
  1593. histogram[x] = Math.max(histogram[x] || 0, y);
  1594. });
  1595.  
  1596. var ctx = this._canvas.getContext("2d");
  1597. this._clear(ctx);
  1598.  
  1599.  
  1600. height = height + 1;
  1601.  
  1602. ctx.beginPath();
  1603. var initialY = 0;
  1604. for (var k = 0; k < histogram.length; k++) {
  1605. if (histogram[k]) {
  1606. initialY = histogram[k];
  1607. break;
  1608. }
  1609. }
  1610. ctx.moveTo(0, height - initialY);
  1611.  
  1612. for (var x = 0; x < histogram.length; x++) {
  1613. if (!histogram[x])
  1614. continue;
  1615. ctx.lineTo(x, height - histogram[x]);
  1616. }
  1617.  
  1618. ctx.lineWidth = 0.5;
  1619. ctx.strokeStyle = "rgba(20,0,0,0.8)";
  1620. ctx.stroke();
  1621.  
  1622. ctx.fillStyle = "rgba(214,225,254, 0.8);";
  1623. ctx.lineTo(width, 60);
  1624. ctx.lineTo(0, 60);
  1625. ctx.lineTo(0, height - initialY);
  1626. ctx.fill();
  1627. ctx.closePath();
  1628.  
  1629. this._maxHeapSizeLabel.textContent = Number.bytesToString(maxUsedHeapSize);
  1630. this._minHeapSizeLabel.textContent = Number.bytesToString(minUsedHeapSize);
  1631. },
  1632.  
  1633. _clear: function(ctx)
  1634. {
  1635. ctx.fillStyle = "rgba(255,255,255,0.8)";
  1636. ctx.fillRect(0, 0, this._canvas.width, this._canvas.height);
  1637. },
  1638. }
  1639.  
  1640.  
  1641. WebInspector.TimelineCategoryStrips = function(model)
  1642. {
  1643. this._model = model;
  1644. this.element = document.createElement("canvas");
  1645. this._context = this.element.getContext("2d");
  1646.  
  1647. this._fillStyles = {};
  1648. var categories = WebInspector.TimelinePresentationModel.categories();
  1649. for (var category in categories)
  1650. this._fillStyles[category] = WebInspector.TimelinePresentationModel.createFillStyleForCategory(this._context, 0, WebInspector.TimelineCategoryStrips._innerStripHeight, categories[category]);
  1651.  
  1652. this._disabledCategoryFillStyle = WebInspector.TimelinePresentationModel.createFillStyle(this._context, 0, WebInspector.TimelineCategoryStrips._innerStripHeight,
  1653. "rgb(218, 218, 218)", "rgb(170, 170, 170)", "rgb(143, 143, 143)");
  1654.  
  1655. this._disabledCategoryBorderStyle = "rgb(143, 143, 143)";
  1656. }
  1657.  
  1658.  
  1659. WebInspector.TimelineCategoryStrips._canvasHeight = 60;
  1660.  
  1661. WebInspector.TimelineCategoryStrips._numberOfStrips = 3;
  1662.  
  1663. WebInspector.TimelineCategoryStrips._stripHeight = Math.round(WebInspector.TimelineCategoryStrips._canvasHeight  / WebInspector.TimelineCategoryStrips._numberOfStrips);
  1664.  
  1665. WebInspector.TimelineCategoryStrips._stripPadding = 4;
  1666.  
  1667. WebInspector.TimelineCategoryStrips._innerStripHeight = WebInspector.TimelineCategoryStrips._stripHeight - 2 * WebInspector.TimelineCategoryStrips._stripPadding;
  1668.  
  1669. WebInspector.TimelineCategoryStrips.prototype = {
  1670. update: function()
  1671. {
  1672.  
  1673. this.element.width = this.element.parentElement.clientWidth;
  1674. this.element.height = WebInspector.TimelineCategoryStrips._canvasHeight;
  1675.  
  1676. var timeOffset = this._model.minimumRecordTime();
  1677. var timeSpan = this._model.maximumRecordTime() - timeOffset;
  1678. var scale = this.element.width / timeSpan;
  1679.  
  1680. var lastBarByGroup = [];
  1681.  
  1682. this._context.fillStyle = "rgba(0, 0, 0, 0.05)";
  1683. for (var i = 1; i < WebInspector.TimelineCategoryStrips._numberOfStrips; i += 2)
  1684. this._context.fillRect(0.5, i * WebInspector.TimelineCategoryStrips._stripHeight + 0.5, this.element.width, WebInspector.TimelineCategoryStrips._stripHeight);
  1685.  
  1686. function appendRecord(record)
  1687. {
  1688. var isLong = WebInspector.TimelineModel.durationInSeconds(record) > WebInspector.TimelinePresentationModel.shortRecordThreshold;
  1689. if (!(this._showShortEvents || isLong))
  1690. return;
  1691. if (record.type === WebInspector.TimelineModel.RecordType.BeginFrame)
  1692. return;
  1693. var recordStart = Math.floor((WebInspector.TimelineModel.startTimeInSeconds(record) - timeOffset) * scale);
  1694. var recordEnd = Math.ceil((WebInspector.TimelineModel.endTimeInSeconds(record) - timeOffset) * scale);
  1695. var category = WebInspector.TimelinePresentationModel.categoryForRecord(record);
  1696. if (category.overviewStripGroupIndex < 0)
  1697. return;
  1698. var bar = lastBarByGroup[category.overviewStripGroupIndex];
  1699.  
  1700. const barsMergeThreshold = 2;
  1701. if (bar && bar.category === category && bar.end + barsMergeThreshold >= recordStart) {
  1702. if (recordEnd > bar.end)
  1703. bar.end = recordEnd;
  1704. return;
  1705. }
  1706. if (bar)
  1707. this._renderBar(bar.start, bar.end, bar.category);
  1708. lastBarByGroup[category.overviewStripGroupIndex] = { start: recordStart, end: recordEnd, category: category };
  1709. }
  1710. WebInspector.TimelinePresentationModel.forAllRecords(this._model.records, appendRecord.bind(this));
  1711. for (var i = 0; i < lastBarByGroup.length; ++i) {
  1712. if (lastBarByGroup[i])
  1713. this._renderBar(lastBarByGroup[i].start, lastBarByGroup[i].end, lastBarByGroup[i].category);
  1714. }
  1715. },
  1716.  
  1717.  
  1718. setShowShortEvents: function(value)
  1719. {
  1720. this._showShortEvents = value;
  1721. this.update();
  1722. },
  1723.  
  1724. _renderBar: function(begin, end, category)
  1725. {
  1726. var x = begin + 0.5;
  1727. var y = category.overviewStripGroupIndex * WebInspector.TimelineCategoryStrips._stripHeight + WebInspector.TimelineCategoryStrips._stripPadding + 0.5;
  1728. var width = Math.max(end - begin, 1);
  1729.  
  1730. this._context.save();
  1731. this._context.translate(x, y);
  1732. this._context.fillStyle = category.hidden ? this._disabledCategoryFillStyle : this._fillStyles[category.name];
  1733. this._context.fillRect(0, 0, width, WebInspector.TimelineCategoryStrips._innerStripHeight);
  1734. this._context.strokeStyle = category.hidden ? this._disabledCategoryBorderStyle : category.borderColor;
  1735. this._context.strokeRect(0, 0, width, WebInspector.TimelineCategoryStrips._innerStripHeight);
  1736. this._context.restore();
  1737. }
  1738. }
  1739.  
  1740.  
  1741. WebInspector.TimelineFrameOverview = function(model)
  1742. {
  1743. WebInspector.View.call(this);
  1744. this.element = document.createElement("canvas");
  1745. this.element.className = "timeline-frame-overview-bars fill";
  1746. this._model = model;
  1747. this.reset();
  1748.  
  1749. this._outerPadding = 4;
  1750. this._maxInnerBarWidth = 10;
  1751.  
  1752.  
  1753. this._actualPadding = 5;
  1754. this._actualOuterBarWidth = this._maxInnerBarWidth + this._actualPadding;
  1755.  
  1756. this._context = this.element.getContext("2d");
  1757.  
  1758. this._fillStyles = {};
  1759. var categories = WebInspector.TimelinePresentationModel.categories();
  1760. for (var category in categories)
  1761. this._fillStyles[category] = WebInspector.TimelinePresentationModel.createFillStyleForCategory(this._context, this._maxInnerBarWidth, 0, categories[category]);
  1762. }
  1763.  
  1764. WebInspector.TimelineFrameOverview.prototype = {
  1765. reset: function()
  1766. {
  1767. this._recordsPerBar = 1;
  1768. this._barTimes = [];
  1769. this._frames = [];
  1770. },
  1771.  
  1772. update: function()
  1773. {
  1774. const minBarWidth = 4;
  1775. this._framesPerBar = Math.max(1, this._frames.length * minBarWidth / this.element.clientWidth);
  1776. this._barTimes = [];
  1777. var visibleFrames = this._aggregateFrames(this._framesPerBar);
  1778.  
  1779. const paddingTop = 4;
  1780.  
  1781.  
  1782.  
  1783. const targetFPS = 30;
  1784. var fullBarLength = 1.0 / targetFPS;
  1785. if (fullBarLength < this._medianFrameLength)
  1786. fullBarLength = Math.min(this._medianFrameLength * 2, this._maxFrameLength);
  1787.  
  1788. var scale = (this.element.clientHeight - paddingTop) / fullBarLength;
  1789. this._renderBars(visibleFrames, scale);
  1790. },
  1791.  
  1792.  
  1793. addFrame: function(frame)
  1794. {
  1795. this._frames.push(frame);
  1796. },
  1797.  
  1798. framePosition: function(frame)
  1799. {
  1800. var frameNumber = this._frames.indexOf(frame);
  1801. if (frameNumber < 0)
  1802. return;
  1803. var barNumber = Math.floor(frameNumber / this._framesPerBar);
  1804. var firstBar = this._framesPerBar > 1 ? barNumber : Math.max(barNumber - 1, 0);
  1805. var lastBar = this._framesPerBar > 1 ? barNumber : Math.min(barNumber + 1, this._barTimes.length - 1);
  1806. return {
  1807. start: Math.ceil(this._barNumberToScreenPosition(firstBar) - this._actualPadding / 2),
  1808. end: Math.floor(this._barNumberToScreenPosition(lastBar + 1) - this._actualPadding / 2)
  1809. }
  1810. },
  1811.  
  1812.  
  1813. _aggregateFrames: function(framesPerBar)
  1814. {
  1815. var visibleFrames = [];
  1816. var durations = [];
  1817.  
  1818. this._maxFrameLength = 0;
  1819.  
  1820. for (var barNumber = 0, currentFrame = 0; currentFrame < this._frames.length; ++barNumber) {
  1821. var barStartTime = this._frames[currentFrame].startTime;
  1822. var longestFrame = null;
  1823.  
  1824. for (var lastFrame = Math.min(Math.floor((barNumber + 1) * framesPerBar), this._frames.length);
  1825. currentFrame < lastFrame; ++currentFrame) {
  1826. if (!longestFrame || longestFrame.duration < this._frames[currentFrame].duration)
  1827. longestFrame = this._frames[currentFrame];
  1828. }
  1829. var barEndTime = this._frames[currentFrame - 1].endTime;
  1830. if (longestFrame) {
  1831. this._maxFrameLength = Math.max(this._maxFrameLength, longestFrame.duration);
  1832. visibleFrames.push(longestFrame);
  1833. this._barTimes.push({ startTime: barStartTime, endTime: barEndTime });
  1834. durations.push(longestFrame.duration);
  1835. }
  1836. }
  1837. this._medianFrameLength = durations.qselect(Math.floor(durations.length / 2));
  1838. return visibleFrames;
  1839. },
  1840.  
  1841.  
  1842. _renderBars: function(frames, scale)
  1843. {
  1844.  
  1845. this.element.width = this.element.clientWidth;
  1846. this.element.height = this.element.clientHeight;
  1847.  
  1848. const maxPadding = 5;
  1849. this._actualOuterBarWidth = Math.min((this.element.width - 2 * this._outerPadding) / frames.length, this._maxInnerBarWidth + maxPadding);
  1850. this._actualPadding = Math.min(Math.floor(this._actualOuterBarWidth / 3), maxPadding);
  1851.  
  1852. var barWidth = this._actualOuterBarWidth - this._actualPadding;
  1853. for (var i = 0; i < frames.length; ++i)
  1854. this._renderBar(this._barNumberToScreenPosition(i), barWidth, frames[i], scale);
  1855.  
  1856. this._drawFPSMarks(scale);
  1857. },
  1858.  
  1859.  
  1860. _barNumberToScreenPosition: function(n)
  1861. {
  1862. return this._outerPadding + this._actualOuterBarWidth * n;
  1863. },
  1864.  
  1865.  
  1866. _drawFPSMarks: function(scale)
  1867. {
  1868. const fpsMarks = [30, 60];
  1869.  
  1870. this._context.save();
  1871. this._context.beginPath();
  1872. this._context.font = "9px monospace";
  1873. this._context.textAlign = "right";
  1874. this._context.textBaseline = "top";
  1875.  
  1876. const labelPadding = 2;
  1877. var lineHeight = 12;
  1878. var labelTopMargin = 0;
  1879.  
  1880. for (var i = 0; i < fpsMarks.length; ++i) {
  1881. var fps = fpsMarks[i];
  1882.  
  1883. var y = this.element.height - Math.floor(1.0 / fps * scale) - 0.5;
  1884. var label = fps + " FPS ";
  1885. var labelWidth = this._context.measureText(label).width;
  1886. var labelX = this.element.width;
  1887. var labelY;
  1888.  
  1889. if (labelTopMargin < y - lineHeight)
  1890. labelY = y - lineHeight;
  1891. else if (y + lineHeight < this.element.height)
  1892. labelY = y;
  1893. else
  1894. break; 
  1895.  
  1896. this._context.moveTo(0, y);
  1897. this._context.lineTo(this.element.width, y);
  1898.  
  1899. this._context.fillStyle = "rgba(255, 255, 255, 0.75)";
  1900. this._context.fillRect(labelX - labelWidth - labelPadding, labelY, labelWidth + 2 * labelPadding, lineHeight);
  1901. this._context.fillStyle = "rgb(0, 0, 0)";
  1902. this._context.fillText(label, labelX, labelY);
  1903. labelTopMargin = labelY + lineHeight;
  1904. }
  1905. this._context.strokeStyle = "rgb(51, 51, 51)";
  1906. this._context.stroke();
  1907. this._context.restore();
  1908. },
  1909.  
  1910. _renderBar: function(left, width, frame, scale)
  1911. {
  1912. var categories = Object.keys(WebInspector.TimelinePresentationModel.categories());
  1913. if (!categories.length)
  1914. return;
  1915. var x = Math.floor(left) + 0.5;
  1916. width = Math.floor(width);
  1917.  
  1918. for (var i = 0, bottomOffset = this.element.height; i < categories.length; ++i) {
  1919. var category = categories[i];
  1920. var duration = frame.timeByCategory[category];
  1921.  
  1922. if (!duration)
  1923. continue;
  1924. var height = duration * scale;
  1925. var y = Math.floor(bottomOffset - height) + 0.5;
  1926.  
  1927. this._context.save();
  1928. this._context.translate(x, 0);
  1929. this._context.scale(width / this._maxInnerBarWidth, 1);
  1930. this._context.fillStyle = this._fillStyles[category];
  1931. this._context.fillRect(0, y, this._maxInnerBarWidth, Math.floor(height));
  1932. this._context.restore();
  1933.  
  1934. this._context.strokeStyle = WebInspector.TimelinePresentationModel.categories()[category].borderColor;
  1935. this._context.strokeRect(x, y, width, Math.floor(height));
  1936. bottomOffset -= height - 1;
  1937. }
  1938.  
  1939. var nonCPUTime = frame.duration - frame.cpuTime;
  1940. var y0 = Math.floor(bottomOffset - nonCPUTime * scale) + 0.5;
  1941. var y1 = Math.floor(bottomOffset) + 0.5;
  1942.  
  1943. this._context.strokeStyle = "rgb(90, 90, 90)";
  1944. this._context.beginPath();
  1945. this._context.moveTo(x, y1);
  1946. this._context.lineTo(x, y0);
  1947. this._context.lineTo(x + width, y0);
  1948. this._context.lineTo(x + width, y1);
  1949. this._context.stroke();
  1950. },
  1951.  
  1952. getWindowTimes: function(windowLeft, windowRight)
  1953. {
  1954. var windowSpan = this.element.clientWidth;
  1955. var leftOffset = windowLeft * windowSpan - this._outerPadding + this._actualPadding;
  1956. var rightOffset = windowRight * windowSpan - this._outerPadding;
  1957. var bars = this.element.children;
  1958. var firstBar = Math.floor(Math.max(leftOffset, 0) / this._actualOuterBarWidth);
  1959. var lastBar = Math.min(Math.floor(rightOffset / this._actualOuterBarWidth), this._barTimes.length - 1);
  1960. const snapToRightTolerancePixels = 3;
  1961. return {
  1962. startTime: firstBar >= this._barTimes.length ? Infinity : this._barTimes[firstBar].startTime,
  1963. endTime: rightOffset + snapToRightTolerancePixels > windowSpan ? Infinity : this._barTimes[lastBar].endTime
  1964. }
  1965. },
  1966.  
  1967. __proto__: WebInspector.View.prototype
  1968. }
  1969.  
  1970.  
  1971. WebInspector.TimelineWindowFilter = function(pane)
  1972. {
  1973. this._pane = pane;
  1974. }
  1975.  
  1976. WebInspector.TimelineWindowFilter.prototype = {
  1977.  
  1978. accept: function(record)
  1979. {
  1980. return record.lastChildEndTime >= this._pane._windowStartTime && record.startTime <= this._pane._windowEndTime;
  1981. }
  1982. }
  1983. ;
  1984.  
  1985.  
  1986.  
  1987. WebInspector.TimelinePresentationModel = function()
  1988. {
  1989. this._linkifier = new WebInspector.Linkifier();
  1990. this._glueRecords = false;
  1991. this._filters = [];
  1992. this.reset();
  1993. }
  1994.  
  1995. WebInspector.TimelinePresentationModel.shortRecordThreshold = 0.015;
  1996.  
  1997. WebInspector.TimelinePresentationModel.categories = function()
  1998. {
  1999. if (WebInspector.TimelinePresentationModel._categories)
  2000. return WebInspector.TimelinePresentationModel._categories;
  2001. WebInspector.TimelinePresentationModel._categories = {
  2002. program: new WebInspector.TimelineCategory("program", WebInspector.UIString("Program"), -1, "#BBBBBB", "#DDDDDD", "#FFFFFF"),
  2003. loading: new WebInspector.TimelineCategory("loading", WebInspector.UIString("Loading"), 0, "#5A8BCC", "#8EB6E9", "#70A2E3"),
  2004. scripting: new WebInspector.TimelineCategory("scripting", WebInspector.UIString("Scripting"), 1, "#D8AA34", "#F3D07A", "#F1C453"),
  2005. rendering: new WebInspector.TimelineCategory("rendering", WebInspector.UIString("Rendering"), 2, "#8266CC", "#AF9AEB", "#9A7EE6"),
  2006. painting: new WebInspector.TimelineCategory("painting", WebInspector.UIString("Painting"), 2, "#5FA050", "#8DC286", "#71B363")
  2007. };
  2008. return WebInspector.TimelinePresentationModel._categories;
  2009. };
  2010.  
  2011.  
  2012. WebInspector.TimelinePresentationModel._initRecordStyles = function()
  2013. {
  2014. if (WebInspector.TimelinePresentationModel._recordStylesMap)
  2015. return WebInspector.TimelinePresentationModel._recordStylesMap;
  2016.  
  2017. var recordTypes = WebInspector.TimelineModel.RecordType;
  2018. var categories = WebInspector.TimelinePresentationModel.categories();
  2019.  
  2020. var recordStyles = {};
  2021. recordStyles[recordTypes.Root] = { title: "#root", category: categories["loading"] };
  2022. recordStyles[recordTypes.Program] = { title: WebInspector.UIString("Program"), category: categories["program"] };
  2023. recordStyles[recordTypes.EventDispatch] = { title: WebInspector.UIString("Event"), category: categories["scripting"] };
  2024. recordStyles[recordTypes.BeginFrame] = { title: WebInspector.UIString("Frame Start"), category: categories["rendering"] };
  2025. recordStyles[recordTypes.ScheduleStyleRecalculation] = { title: WebInspector.UIString("Schedule Style Recalculation"), category: categories["rendering"] };
  2026. recordStyles[recordTypes.RecalculateStyles] = { title: WebInspector.UIString("Recalculate Style"), category: categories["rendering"] };
  2027. recordStyles[recordTypes.InvalidateLayout] = { title: WebInspector.UIString("Invalidate Layout"), category: categories["rendering"] };
  2028. recordStyles[recordTypes.Layout] = { title: WebInspector.UIString("Layout"), category: categories["rendering"] };
  2029. recordStyles[recordTypes.Paint] = { title: WebInspector.UIString("Paint"), category: categories["painting"] };
  2030. recordStyles[recordTypes.ScrollLayer] = { title: WebInspector.UIString("Scroll"), category: categories["painting"] };
  2031. recordStyles[recordTypes.DecodeImage] = { title: WebInspector.UIString("Image Decode"), category: categories["painting"] };
  2032. recordStyles[recordTypes.ResizeImage] = { title: WebInspector.UIString("Image Resize"), category: categories["painting"] };
  2033. recordStyles[recordTypes.CompositeLayers] = { title: WebInspector.UIString("Composite Layers"), category: categories["painting"] };
  2034. recordStyles[recordTypes.ParseHTML] = { title: WebInspector.UIString("Parse HTML"), category: categories["loading"] };
  2035. recordStyles[recordTypes.TimerInstall] = { title: WebInspector.UIString("Install Timer"), category: categories["scripting"] };
  2036. recordStyles[recordTypes.TimerRemove] = { title: WebInspector.UIString("Remove Timer"), category: categories["scripting"] };
  2037. recordStyles[recordTypes.TimerFire] = { title: WebInspector.UIString("Timer Fired"), category: categories["scripting"] };
  2038. recordStyles[recordTypes.XHRReadyStateChange] = { title: WebInspector.UIString("XHR Ready State Change"), category: categories["scripting"] };
  2039. recordStyles[recordTypes.XHRLoad] = { title: WebInspector.UIString("XHR Load"), category: categories["scripting"] };
  2040. recordStyles[recordTypes.EvaluateScript] = { title: WebInspector.UIString("Evaluate Script"), category: categories["scripting"] };
  2041. recordStyles[recordTypes.ResourceSendRequest] = { title: WebInspector.UIString("Send Request"), category: categories["loading"] };
  2042. recordStyles[recordTypes.ResourceReceiveResponse] = { title: WebInspector.UIString("Receive Response"), category: categories["loading"] };
  2043. recordStyles[recordTypes.ResourceFinish] = { title: WebInspector.UIString("Finish Loading"), category: categories["loading"] };
  2044. recordStyles[recordTypes.FunctionCall] = { title: WebInspector.UIString("Function Call"), category: categories["scripting"] };
  2045. recordStyles[recordTypes.ResourceReceivedData] = { title: WebInspector.UIString("Receive Data"), category: categories["loading"] };
  2046. recordStyles[recordTypes.GCEvent] = { title: WebInspector.UIString("GC Event"), category: categories["scripting"] };
  2047. recordStyles[recordTypes.MarkDOMContent] = { title: WebInspector.UIString("DOMContentLoaded event"), category: categories["scripting"] };
  2048. recordStyles[recordTypes.MarkLoad] = { title: WebInspector.UIString("Load event"), category: categories["scripting"] };
  2049. recordStyles[recordTypes.TimeStamp] = { title: WebInspector.UIString("Stamp"), category: categories["scripting"] };
  2050. recordStyles[recordTypes.Time] = { title: WebInspector.UIString("Time"), category: categories["scripting"] };
  2051. recordStyles[recordTypes.TimeEnd] = { title: WebInspector.UIString("Time End"), category: categories["scripting"] };
  2052. recordStyles[recordTypes.ScheduleResourceRequest] = { title: WebInspector.UIString("Schedule Request"), category: categories["loading"] };
  2053. recordStyles[recordTypes.RequestAnimationFrame] = { title: WebInspector.UIString("Request Animation Frame"), category: categories["scripting"] };
  2054. recordStyles[recordTypes.CancelAnimationFrame] = { title: WebInspector.UIString("Cancel Animation Frame"), category: categories["scripting"] };
  2055. recordStyles[recordTypes.FireAnimationFrame] = { title: WebInspector.UIString("Animation Frame Fired"), category: categories["scripting"] };
  2056.  
  2057. WebInspector.TimelinePresentationModel._recordStylesMap = recordStyles;
  2058. return recordStyles;
  2059. }
  2060.  
  2061.  
  2062. WebInspector.TimelinePresentationModel.recordStyle = function(record)
  2063. {
  2064. var recordStyles = WebInspector.TimelinePresentationModel._initRecordStyles();
  2065. var result = recordStyles[record.type];
  2066. if (!result) {
  2067. result = {
  2068. title: WebInspector.UIString("Unknown: %s", record.type),
  2069. category: WebInspector.TimelinePresentationModel.categories()["program"]
  2070. };
  2071. recordStyles[record.type] = result;
  2072. }
  2073. return result;
  2074. }
  2075.  
  2076. WebInspector.TimelinePresentationModel.categoryForRecord = function(record)
  2077. {
  2078. return WebInspector.TimelinePresentationModel.recordStyle(record).category;
  2079. }
  2080.  
  2081. WebInspector.TimelinePresentationModel.isEventDivider = function(record)
  2082. {
  2083. var recordTypes = WebInspector.TimelineModel.RecordType;
  2084. if (record.type === recordTypes.TimeStamp)
  2085. return true;
  2086. if (record.type === recordTypes.MarkDOMContent || record.type === recordTypes.MarkLoad) {
  2087. var mainFrame = WebInspector.resourceTreeModel.mainFrame;
  2088. if (mainFrame && mainFrame.id === record.frameId)
  2089. return true;
  2090. }
  2091. return false;
  2092. }
  2093.  
  2094.  
  2095. WebInspector.TimelinePresentationModel.forAllRecords = function(recordsArray, preOrderCallback, postOrderCallback)
  2096. {
  2097. if (!recordsArray)
  2098. return;
  2099. var stack = [{array: recordsArray, index: 0}];
  2100. while (stack.length) {
  2101. var entry = stack[stack.length - 1];
  2102. var records = entry.array;
  2103. if (entry.index < records.length) {
  2104. var record = records[entry.index];
  2105. if (preOrderCallback && preOrderCallback(record))
  2106. return;
  2107. if (record.children)
  2108. stack.push({array: record.children, index: 0, record: record});
  2109. else if (postOrderCallback && postOrderCallback(record))
  2110. return;
  2111. ++entry.index;
  2112. } else {
  2113. if (entry.record && postOrderCallback && postOrderCallback(entry.record))
  2114. return;
  2115. stack.pop();
  2116. }
  2117. }
  2118. }
  2119.  
  2120.  
  2121. WebInspector.TimelinePresentationModel.needsPreviewElement = function(recordType)
  2122. {
  2123. if (!recordType)
  2124. return false;
  2125. const recordTypes = WebInspector.TimelineModel.RecordType;
  2126. switch (recordType) {
  2127. case recordTypes.ScheduleResourceRequest:
  2128. case recordTypes.ResourceSendRequest:
  2129. case recordTypes.ResourceReceiveResponse:
  2130. case recordTypes.ResourceReceivedData:
  2131. case recordTypes.ResourceFinish:
  2132. return true;
  2133. default:
  2134. return false;
  2135. }
  2136. }
  2137.  
  2138.  
  2139. WebInspector.TimelinePresentationModel.createEventDivider = function(recordType, title)
  2140. {
  2141. var eventDivider = document.createElement("div");
  2142. eventDivider.className = "resources-event-divider";
  2143. var recordTypes = WebInspector.TimelineModel.RecordType;
  2144.  
  2145. if (recordType === recordTypes.MarkDOMContent)
  2146. eventDivider.className += " resources-blue-divider";
  2147. else if (recordType === recordTypes.MarkLoad)
  2148. eventDivider.className += " resources-red-divider";
  2149. else if (recordType === recordTypes.TimeStamp)
  2150. eventDivider.className += " resources-orange-divider";
  2151. else if (recordType === recordTypes.BeginFrame)
  2152. eventDivider.className += " timeline-frame-divider";
  2153.  
  2154. if (title)
  2155. eventDivider.title = title;
  2156.  
  2157. return eventDivider;
  2158. }
  2159.  
  2160. WebInspector.TimelinePresentationModel._hiddenRecords = { }
  2161. WebInspector.TimelinePresentationModel._hiddenRecords[WebInspector.TimelineModel.RecordType.MarkDOMContent] = 1;
  2162. WebInspector.TimelinePresentationModel._hiddenRecords[WebInspector.TimelineModel.RecordType.MarkLoad] = 1;
  2163. WebInspector.TimelinePresentationModel._hiddenRecords[WebInspector.TimelineModel.RecordType.ScheduleStyleRecalculation] = 1;
  2164. WebInspector.TimelinePresentationModel._hiddenRecords[WebInspector.TimelineModel.RecordType.InvalidateLayout] = 1;
  2165.  
  2166. WebInspector.TimelinePresentationModel.prototype = {
  2167.  
  2168. addFilter: function(filter)
  2169. {
  2170. this._filters.push(filter);
  2171. },
  2172.  
  2173.  
  2174. removeFilter: function(filter)
  2175. {
  2176. var index = this._filters.indexOf(filter);
  2177. if (index !== -1)
  2178. this._filters.splice(index, 1);
  2179. },
  2180.  
  2181. rootRecord: function()
  2182. {
  2183. return this._rootRecord;
  2184. },
  2185.  
  2186. frames: function()
  2187. {
  2188. return this._frames;
  2189. },
  2190.  
  2191. reset: function()
  2192. {
  2193. this._linkifier.reset();
  2194. this._rootRecord = new WebInspector.TimelinePresentationModel.Record(this, { type: WebInspector.TimelineModel.RecordType.Root }, null, null, null, false);
  2195. this._sendRequestRecords = {};
  2196. this._scheduledResourceRequests = {};
  2197. this._timerRecords = {};
  2198. this._requestAnimationFrameRecords = {};
  2199. this._timeRecords = {};
  2200. this._frames = [];
  2201. this._minimumRecordTime = -1;
  2202. this._lastInvalidateLayout = {};
  2203. this._lastScheduleStyleRecalculation = {};
  2204. },
  2205.  
  2206. addFrame: function(frame)
  2207. {
  2208. this._frames.push(frame);
  2209. },
  2210.  
  2211. addRecord: function(record)
  2212. {
  2213. if (this._minimumRecordTime === -1 || record.startTime < this._minimumRecordTime)
  2214. this._minimumRecordTime = WebInspector.TimelineModel.startTimeInSeconds(record);
  2215.  
  2216. var records;
  2217. if (record.type === WebInspector.TimelineModel.RecordType.Program)
  2218. records = record.children;
  2219. else
  2220. records = [record];
  2221.  
  2222. var formattedRecords = [];
  2223. var recordsCount = records.length;
  2224. for (var i = 0; i < recordsCount; ++i)
  2225. formattedRecords.push(this._innerAddRecord(records[i], this._rootRecord));
  2226. return formattedRecords;
  2227. },
  2228.  
  2229. _innerAddRecord: function(record, parentRecord)
  2230. {
  2231. const recordTypes = WebInspector.TimelineModel.RecordType;
  2232. var isHiddenRecord = record.type in WebInspector.TimelinePresentationModel._hiddenRecords;
  2233. var origin;
  2234. if (!isHiddenRecord) {
  2235. var newParentRecord = this._findParentRecord(record);
  2236. if (newParentRecord) {
  2237. origin = parentRecord;
  2238. parentRecord = newParentRecord;
  2239. }
  2240. }
  2241.  
  2242. var children = record.children;
  2243. var scriptDetails;
  2244. if (record.data && record.data["scriptName"]) {
  2245. scriptDetails = {
  2246. scriptName: record.data["scriptName"],
  2247. scriptLine: record.data["scriptLine"]
  2248. }
  2249. };
  2250.  
  2251. if ((record.type === recordTypes.TimerFire || record.type === recordTypes.FireAnimationFrame) && children && children.length) {
  2252. var childRecord = children[0];
  2253. if (childRecord.type === recordTypes.FunctionCall) {
  2254. scriptDetails = {
  2255. scriptName: childRecord.data["scriptName"],
  2256. scriptLine: childRecord.data["scriptLine"]
  2257. };
  2258. children = childRecord.children.concat(children.slice(1));
  2259. }
  2260. }
  2261.  
  2262. var formattedRecord = new WebInspector.TimelinePresentationModel.Record(this, record, parentRecord, origin, scriptDetails, isHiddenRecord);
  2263.  
  2264. if (isHiddenRecord)
  2265. return formattedRecord;
  2266.  
  2267. formattedRecord.collapsed = (parentRecord === this._rootRecord);
  2268.  
  2269. var childrenCount = children ? children.length : 0;
  2270. for (var i = 0; i < childrenCount; ++i)
  2271. this._innerAddRecord(children[i], formattedRecord);
  2272.  
  2273. formattedRecord.calculateAggregatedStats(WebInspector.TimelinePresentationModel.categories());
  2274.  
  2275. if (origin) {
  2276. var lastChildEndTime = formattedRecord.lastChildEndTime;
  2277. var aggregatedStats = formattedRecord.aggregatedStats;
  2278. for (var currentRecord = formattedRecord.parent; !currentRecord.isRoot(); currentRecord = currentRecord.parent) {
  2279. currentRecord._cpuTime += formattedRecord._cpuTime;
  2280. if (currentRecord.lastChildEndTime < lastChildEndTime)
  2281. currentRecord.lastChildEndTime = lastChildEndTime;
  2282. for (var category in aggregatedStats)
  2283. currentRecord.aggregatedStats[category] += aggregatedStats[category];
  2284. }
  2285. }
  2286. origin = formattedRecord.origin();
  2287. if (!origin.isRoot()) {
  2288. origin.selfTime -= formattedRecord.endTime - formattedRecord.startTime;
  2289. }
  2290. return formattedRecord;
  2291. },
  2292.  
  2293. _findParentRecord: function(record)
  2294. {
  2295. if (!this._glueRecords)
  2296. return null;
  2297. var recordTypes = WebInspector.TimelineModel.RecordType;
  2298.  
  2299. switch (record.type) {
  2300. case recordTypes.ResourceReceiveResponse:
  2301. case recordTypes.ResourceFinish:
  2302. case recordTypes.ResourceReceivedData:
  2303. return this._sendRequestRecords[record.data["requestId"]];
  2304.  
  2305. case recordTypes.ResourceSendRequest:
  2306. return this._rootRecord;
  2307.  
  2308. case recordTypes.TimerFire:
  2309. return this._timerRecords[record.data["timerId"]];
  2310.  
  2311. case recordTypes.ResourceSendRequest:
  2312. return this._scheduledResourceRequests[record.data["url"]];
  2313.  
  2314. case recordTypes.FireAnimationFrame:
  2315. return this._requestAnimationFrameRecords[record.data["id"]];
  2316.  
  2317. case recordTypes.Time:
  2318. return this._rootRecord;
  2319.  
  2320. case recordTypes.TimeEnd:
  2321. return this._timeRecords[record.data["message"]];
  2322. }
  2323. },
  2324.  
  2325. setGlueRecords: function(glue)
  2326. {
  2327. this._glueRecords = glue;
  2328. },
  2329.  
  2330. invalidateFilteredRecords: function()
  2331. {
  2332. delete this._filteredRecords;
  2333. },
  2334.  
  2335. filteredRecords: function()
  2336. {
  2337. if (this._filteredRecords)
  2338. return this._filteredRecords;
  2339.  
  2340. var recordsInWindow = [];
  2341.  
  2342. var stack = [{children: this._rootRecord.children, index: 0, parentIsCollapsed: false}];
  2343. while (stack.length) {
  2344. var entry = stack[stack.length - 1];
  2345. var records = entry.children;
  2346. if (records && entry.index < records.length) {
  2347. var record = records[entry.index];
  2348. ++entry.index;
  2349.  
  2350. if (this.isVisible(record)) {
  2351. ++record.parent._invisibleChildrenCount;
  2352. if (!entry.parentIsCollapsed)
  2353. recordsInWindow.push(record);
  2354. }
  2355.  
  2356. record._invisibleChildrenCount = 0;
  2357.  
  2358. stack.push({children: record.children,
  2359. index: 0,
  2360. parentIsCollapsed: (entry.parentIsCollapsed || record.collapsed),
  2361. parentRecord: record,
  2362. windowLengthBeforeChildrenTraversal: recordsInWindow.length});
  2363. } else {
  2364. stack.pop();
  2365. if (entry.parentRecord)
  2366. entry.parentRecord._visibleChildrenCount = recordsInWindow.length - entry.windowLengthBeforeChildrenTraversal;
  2367. }
  2368. }
  2369.  
  2370. this._filteredRecords = recordsInWindow;
  2371. return recordsInWindow;
  2372. },
  2373.  
  2374. filteredFrames: function(startTime, endTime)
  2375. {
  2376. function compareStartTime(value, object)
  2377. {
  2378. return value - object.startTime;
  2379. }
  2380. function compareEndTime(value, object)
  2381. {
  2382. return value - object.endTime;
  2383. }
  2384. var firstFrame = insertionIndexForObjectInListSortedByFunction(startTime, this._frames, compareStartTime);
  2385. var lastFrame = insertionIndexForObjectInListSortedByFunction(endTime, this._frames, compareEndTime);
  2386. while (lastFrame < this._frames.length && this._frames[lastFrame].endTime <= endTime)
  2387. ++lastFrame;
  2388. return this._frames.slice(firstFrame, lastFrame);
  2389. },
  2390.  
  2391. isVisible: function(record)
  2392. {
  2393. for (var i = 0; i < this._filters.length; ++i) {
  2394. if (!this._filters[i].accept(record))
  2395. return false;
  2396. }
  2397. return true;
  2398. },
  2399.  
  2400.  
  2401. generateMainThreadBarPopupContent: function(info)
  2402. {
  2403. var firstTaskIndex = info.firstTaskIndex;
  2404. var lastTaskIndex = info.lastTaskIndex;
  2405. var tasks = info.tasks;
  2406. var messageCount = lastTaskIndex - firstTaskIndex + 1;
  2407. var cpuTime = 0;
  2408.  
  2409. for (var i = firstTaskIndex; i <= lastTaskIndex; ++i) {
  2410. var task = tasks[i];
  2411. cpuTime += task.endTime - task.startTime;
  2412. }
  2413. var startTime = tasks[firstTaskIndex].startTime;
  2414. var endTime = tasks[lastTaskIndex].endTime;
  2415. var duration = endTime - startTime;
  2416. var offset = this._minimumRecordTime;
  2417.  
  2418. var contentHelper = new WebInspector.TimelinePresentationModel.PopupContentHelper(WebInspector.UIString("CPU"));
  2419. var durationText = WebInspector.UIString("%s (at %s)", Number.secondsToString(duration, true),
  2420. Number.secondsToString(startTime - offset, true));
  2421. contentHelper._appendTextRow(WebInspector.UIString("Duration"), durationText);
  2422. contentHelper._appendTextRow(WebInspector.UIString("CPU time"), Number.secondsToString(cpuTime, true));
  2423. contentHelper._appendTextRow(WebInspector.UIString("Message Count"), messageCount);
  2424. return contentHelper._contentTable;
  2425. },
  2426.  
  2427. __proto__: WebInspector.Object.prototype
  2428. }
  2429.  
  2430.  
  2431. WebInspector.TimelinePresentationModel.Record = function(presentationModel, record, parentRecord, origin, scriptDetails, hidden)
  2432. {
  2433. this._linkifier = presentationModel._linkifier;
  2434. this._aggregatedStats = [];
  2435. this._record = record;
  2436. this._children = [];
  2437. if (!hidden && parentRecord) {
  2438. this.parent = parentRecord;
  2439. parentRecord.children.push(this);
  2440. }
  2441. if (origin)
  2442. this._origin = origin;
  2443.  
  2444. this._selfTime = this.endTime - this.startTime;
  2445. this._lastChildEndTime = this.endTime;
  2446. this._startTimeOffset = this.startTime - presentationModel._minimumRecordTime;
  2447.  
  2448. if (record.data && record.data["url"])
  2449. this.url = record.data["url"];
  2450. if (scriptDetails) {
  2451. this.scriptName = scriptDetails.scriptName;
  2452. this.scriptLine = scriptDetails.scriptLine;
  2453. }
  2454. if (parentRecord && parentRecord.callSiteStackTrace)
  2455. this.callSiteStackTrace = parentRecord.callSiteStackTrace;
  2456.  
  2457. var recordTypes = WebInspector.TimelineModel.RecordType;
  2458. switch (record.type) {
  2459. case recordTypes.ResourceSendRequest:
  2460.  
  2461. presentationModel._sendRequestRecords[record.data["requestId"]] = this;
  2462. break;
  2463.  
  2464. case recordTypes.ScheduleResourceRequest:
  2465. presentationModel._scheduledResourceRequests[record.data["url"]] = this;
  2466. break;
  2467.  
  2468. case recordTypes.ResourceReceiveResponse:
  2469. var sendRequestRecord = presentationModel._sendRequestRecords[record.data["requestId"]];
  2470. if (sendRequestRecord) { 
  2471. this.url = sendRequestRecord.url;
  2472.  
  2473. sendRequestRecord._refreshDetails();
  2474. if (sendRequestRecord.parent !== presentationModel._rootRecord && sendRequestRecord.parent.type === recordTypes.ScheduleResourceRequest)
  2475. sendRequestRecord.parent._refreshDetails();
  2476. }
  2477. break;
  2478.  
  2479. case recordTypes.ResourceReceivedData:
  2480. case recordTypes.ResourceFinish:
  2481. var sendRequestRecord = presentationModel._sendRequestRecords[record.data["requestId"]];
  2482. if (sendRequestRecord) 
  2483. this.url = sendRequestRecord.url;
  2484. break;
  2485.  
  2486. case recordTypes.TimerInstall:
  2487. this.timeout = record.data["timeout"];
  2488. this.singleShot = record.data["singleShot"];
  2489. presentationModel._timerRecords[record.data["timerId"]] = this;
  2490. break;
  2491.  
  2492. case recordTypes.TimerFire:
  2493. var timerInstalledRecord = presentationModel._timerRecords[record.data["timerId"]];
  2494. if (timerInstalledRecord) {
  2495. this.callSiteStackTrace = timerInstalledRecord.stackTrace;
  2496. this.timeout = timerInstalledRecord.timeout;
  2497. this.singleShot = timerInstalledRecord.singleShot;
  2498. }
  2499. break;
  2500.  
  2501. case recordTypes.RequestAnimationFrame:
  2502. presentationModel._requestAnimationFrameRecords[record.data["id"]] = this;
  2503. break;
  2504.  
  2505. case recordTypes.FireAnimationFrame:
  2506. var requestAnimationRecord = presentationModel._requestAnimationFrameRecords[record.data["id"]];
  2507. if (requestAnimationRecord)
  2508. this.callSiteStackTrace = requestAnimationRecord.stackTrace;
  2509. break;
  2510.  
  2511. case recordTypes.Time:
  2512. presentationModel._timeRecords[record.data["message"]] = this;
  2513. break;
  2514.  
  2515. case recordTypes.TimeEnd:
  2516. var message = record.data["message"];
  2517. var timeRecord = presentationModel._timeRecords[message];
  2518. delete presentationModel._timeRecords[message];
  2519. if (timeRecord) {
  2520. this.timeRecord = timeRecord;
  2521. timeRecord.timeEndRecord = this;
  2522. var intervalDuration = this.startTime - timeRecord.startTime;
  2523. this.intervalDuration = intervalDuration;
  2524. timeRecord.intervalDuration = intervalDuration;
  2525. }
  2526. break;
  2527.  
  2528. case recordTypes.ScheduleStyleRecalculation:
  2529. presentationModel._lastScheduleStyleRecalculation[this.frameId] = this;
  2530. break;
  2531.  
  2532. case recordTypes.RecalculateStyles:
  2533. var scheduleStyleRecalculationRecord = presentationModel._lastScheduleStyleRecalculation[this.frameId];
  2534. if (!scheduleStyleRecalculationRecord)
  2535. break;
  2536. this.callSiteStackTrace = scheduleStyleRecalculationRecord.stackTrace;
  2537. break;
  2538.  
  2539. case recordTypes.InvalidateLayout:
  2540. presentationModel._lastInvalidateLayout[this.frameId] = this;
  2541. break;
  2542.  
  2543. case recordTypes.Layout:
  2544. var invalidateLayoutRecord = presentationModel._lastInvalidateLayout[this.frameId];
  2545. if (invalidateLayoutRecord)
  2546. this.callSiteStackTrace = invalidateLayoutRecord.stackTrace || invalidateLayoutRecord.callSiteStackTrace;
  2547. if (this.stackTrace)
  2548. this.setHasWarning();
  2549. presentationModel._lastInvalidateLayout[this.frameId] = null;
  2550. break;
  2551. }
  2552. }
  2553.  
  2554. WebInspector.TimelinePresentationModel.Record.prototype = {
  2555. get lastChildEndTime()
  2556. {
  2557. return this._lastChildEndTime;
  2558. },
  2559.  
  2560. set lastChildEndTime(time)
  2561. {
  2562. this._lastChildEndTime = time;
  2563. },
  2564.  
  2565. get selfTime()
  2566. {
  2567. return this._selfTime;
  2568. },
  2569.  
  2570. set selfTime(time)
  2571. {
  2572. this._selfTime = time;
  2573. },
  2574.  
  2575. get cpuTime()
  2576. {
  2577. return this._cpuTime;
  2578. },
  2579.  
  2580. isLong: function()
  2581. {
  2582. return (this._lastChildEndTime - this.startTime) > WebInspector.TimelinePresentationModel.shortRecordThreshold;
  2583. },
  2584.  
  2585.  
  2586. isRoot: function()
  2587. {
  2588. return this.type === WebInspector.TimelineModel.RecordType.Root;
  2589. },
  2590.  
  2591.  
  2592. origin: function()
  2593. {
  2594. return this._origin || this.parent;
  2595. },
  2596.  
  2597.  
  2598. get children()
  2599. {
  2600. return this._children;
  2601. },
  2602.  
  2603.  
  2604. get visibleChildrenCount()
  2605. {
  2606. return this._visibleChildrenCount || 0;
  2607. },
  2608.  
  2609.  
  2610. get invisibleChildrenCount()
  2611. {
  2612. return this._invisibleChildrenCount || 0;
  2613. },
  2614.  
  2615.  
  2616. get category()
  2617. {
  2618. return WebInspector.TimelinePresentationModel.recordStyle(this._record).category
  2619. },
  2620.  
  2621.  
  2622. get title()
  2623. {
  2624. return this.type === WebInspector.TimelineModel.RecordType.TimeStamp ? this._record.data["message"] :
  2625. WebInspector.TimelinePresentationModel.recordStyle(this._record).title;
  2626. },
  2627.  
  2628.  
  2629. get startTime()
  2630. {
  2631. return WebInspector.TimelineModel.startTimeInSeconds(this._record);
  2632. },
  2633.  
  2634.  
  2635. get endTime()
  2636. {
  2637. return WebInspector.TimelineModel.endTimeInSeconds(this._record);
  2638. },
  2639.  
  2640.  
  2641. get data()
  2642. {
  2643. return this._record.data;
  2644. },
  2645.  
  2646.  
  2647. get type()
  2648. {
  2649. return this._record.type;
  2650. },
  2651.  
  2652.  
  2653. get frameId()
  2654. {
  2655. return this._record.frameId;
  2656. },
  2657.  
  2658.  
  2659. get usedHeapSizeDelta()
  2660. {
  2661. return this._record.usedHeapSizeDelta || 0;
  2662. },
  2663.  
  2664.  
  2665. get usedHeapSize()
  2666. {
  2667. return this._record.usedHeapSize;
  2668. },
  2669.  
  2670.  
  2671. get stackTrace()
  2672. {
  2673. if (this._record.stackTrace && this._record.stackTrace.length)
  2674. return this._record.stackTrace;
  2675. return null;
  2676. },
  2677.  
  2678. containsTime: function(time)
  2679. {
  2680. return this.startTime <= time && time <= this.endTime;
  2681. },
  2682.  
  2683.  
  2684. generatePopupContent: function(callback)
  2685. {
  2686. if (WebInspector.TimelinePresentationModel.needsPreviewElement(this.type))
  2687. WebInspector.DOMPresentationUtils.buildImagePreviewContents(this.url, false, this._generatePopupContentWithImagePreview.bind(this, callback));
  2688. else
  2689. this._generatePopupContentWithImagePreview(callback);
  2690. },
  2691.  
  2692.  
  2693. _generatePopupContentWithImagePreview: function(callback, previewElement)
  2694. {
  2695. var contentHelper = new WebInspector.TimelinePresentationModel.PopupContentHelper(this.title);
  2696. var text = WebInspector.UIString("%s (at %s)", Number.secondsToString(this._lastChildEndTime - this.startTime, true),
  2697. Number.secondsToString(this._startTimeOffset));
  2698. contentHelper._appendTextRow(WebInspector.UIString("Duration"), text);
  2699.  
  2700. if (this._children.length) {
  2701. contentHelper._appendTextRow(WebInspector.UIString("Self Time"), Number.secondsToString(this._selfTime, true));
  2702. contentHelper._appendTextRow(WebInspector.UIString("CPU Time"), Number.secondsToString(this._cpuTime, true));
  2703. contentHelper._appendElementRow(WebInspector.UIString("Aggregated Time"),
  2704. WebInspector.TimelinePresentationModel._generateAggregatedInfo(this._aggregatedStats));
  2705. }
  2706. const recordTypes = WebInspector.TimelineModel.RecordType;
  2707.  
  2708.  
  2709. var callSiteStackTraceLabel;
  2710. var callStackLabel;
  2711.  
  2712. switch (this.type) {
  2713. case recordTypes.GCEvent:
  2714. contentHelper._appendTextRow(WebInspector.UIString("Collected"), Number.bytesToString(this.data["usedHeapSizeDelta"]));
  2715. break;
  2716. case recordTypes.TimerInstall:
  2717. case recordTypes.TimerFire:
  2718. case recordTypes.TimerRemove:
  2719. contentHelper._appendTextRow(WebInspector.UIString("Timer ID"), this.data["timerId"]);
  2720. if (typeof this.timeout === "number") {
  2721. contentHelper._appendTextRow(WebInspector.UIString("Timeout"), Number.secondsToString(this.timeout / 1000));
  2722. contentHelper._appendTextRow(WebInspector.UIString("Repeats"), !this.singleShot);
  2723. }
  2724. break;
  2725. case recordTypes.FireAnimationFrame:
  2726. contentHelper._appendTextRow(WebInspector.UIString("Callback ID"), this.data["id"]);
  2727. break;
  2728. case recordTypes.FunctionCall:
  2729. contentHelper._appendElementRow(WebInspector.UIString("Location"), this._linkifyScriptLocation());
  2730. break;
  2731. case recordTypes.ScheduleResourceRequest:
  2732. case recordTypes.ResourceSendRequest:
  2733. case recordTypes.ResourceReceiveResponse:
  2734. case recordTypes.ResourceReceivedData:
  2735. case recordTypes.ResourceFinish:
  2736. contentHelper._appendElementRow(WebInspector.UIString("Resource"), WebInspector.linkifyResourceAsNode(this.url));
  2737. if (previewElement)
  2738. contentHelper._appendElementRow(WebInspector.UIString("Preview"), previewElement);
  2739. if (this.data["requestMethod"])
  2740. contentHelper._appendTextRow(WebInspector.UIString("Request Method"), this.data["requestMethod"]);
  2741. if (typeof this.data["statusCode"] === "number")
  2742. contentHelper._appendTextRow(WebInspector.UIString("Status Code"), this.data["statusCode"]);
  2743. if (this.data["mimeType"])
  2744. contentHelper._appendTextRow(WebInspector.UIString("MIME Type"), this.data["mimeType"]);
  2745. if (this.data["encodedDataLength"])
  2746. contentHelper._appendTextRow(WebInspector.UIString("Encoded Data Length"), WebInspector.UIString("%d Bytes", this.data["encodedDataLength"]));
  2747. break;
  2748. case recordTypes.EvaluateScript:
  2749. if (this.data && this.url)
  2750. contentHelper._appendElementRow(WebInspector.UIString("Script"), this._linkifyLocation(this.url, this.data["lineNumber"]));
  2751. break;
  2752. case recordTypes.Paint:
  2753. contentHelper._appendTextRow(WebInspector.UIString("Location"), WebInspector.UIString("(%d, %d)", this.data["x"], this.data["y"]));
  2754. contentHelper._appendTextRow(WebInspector.UIString("Dimensions"), WebInspector.UIString("%d ├ù %d", this.data["width"], this.data["height"]));
  2755. break;
  2756. case recordTypes.RecalculateStyles: 
  2757. callSiteStackTraceLabel = WebInspector.UIString("Styles invalidated");
  2758. callStackLabel = WebInspector.UIString("Styles recalculation forced");
  2759. break;
  2760. case recordTypes.Layout:
  2761. callSiteStackTraceLabel = WebInspector.UIString("Layout invalidated");
  2762. if (this.stackTrace) {
  2763. callStackLabel = WebInspector.UIString("Layout forced");
  2764. contentHelper._appendTextRow(WebInspector.UIString("Note"), WebInspector.UIString("Forced synchronous layout is a possible performance bottleneck."));
  2765. }
  2766. break;
  2767. case recordTypes.Time:
  2768. case recordTypes.TimeEnd:
  2769. contentHelper._appendTextRow(WebInspector.UIString("Message"), this.data["message"]);
  2770. if (typeof this.intervalDuration === "number")
  2771. contentHelper._appendTextRow(WebInspector.UIString("Interval Duration"), Number.secondsToString(this.intervalDuration, true));
  2772. break;
  2773. default:
  2774. if (this.detailsNode())
  2775. contentHelper._appendElementRow(WebInspector.UIString("Details"), this.detailsNode().childNodes[1].cloneNode());
  2776. break;
  2777. }
  2778.  
  2779. if (this.scriptName && this.type !== recordTypes.FunctionCall)
  2780. contentHelper._appendElementRow(WebInspector.UIString("Function Call"), this._linkifyScriptLocation());
  2781.  
  2782. if (this.usedHeapSize) {
  2783. if (this.usedHeapSizeDelta) {
  2784. var sign = this.usedHeapSizeDelta > 0 ? "+" : "-";
  2785. contentHelper._appendTextRow(WebInspector.UIString("Used Heap Size"),
  2786. WebInspector.UIString("%s (%s%s)", Number.bytesToString(this.usedHeapSize), sign, Number.bytesToString(this.usedHeapSizeDelta)));
  2787. } else if (this.category === WebInspector.TimelinePresentationModel.categories().scripting)
  2788. contentHelper._appendTextRow(WebInspector.UIString("Used Heap Size"), Number.bytesToString(this.usedHeapSize));
  2789. }
  2790.  
  2791. if (this.callSiteStackTrace)
  2792. contentHelper._appendStackTrace(callSiteStackTraceLabel || WebInspector.UIString("Call Site stack"), this.callSiteStackTrace, this._linkifyCallFrame.bind(this));
  2793.  
  2794. if (this.stackTrace)
  2795. contentHelper._appendStackTrace(callStackLabel || WebInspector.UIString("Call Stack"), this.stackTrace, this._linkifyCallFrame.bind(this));
  2796.  
  2797. callback(contentHelper._contentTable);
  2798. },
  2799.  
  2800. _refreshDetails: function()
  2801. {
  2802. delete this._detailsNode;
  2803. },
  2804.  
  2805.  
  2806. detailsNode: function()
  2807. {
  2808. if (typeof this._detailsNode === "undefined") {
  2809. this._detailsNode = this._getRecordDetails();
  2810.  
  2811. if (this._detailsNode) {
  2812. this._detailsNode.insertBefore(document.createTextNode("("), this._detailsNode.firstChild);
  2813. this._detailsNode.appendChild(document.createTextNode(")"));
  2814. }
  2815. }
  2816. return this._detailsNode;
  2817. },
  2818.  
  2819. _createSpanWithText: function(textContent)
  2820. {
  2821. var node = document.createElement("span");
  2822. node.textContent = textContent;
  2823. return node;
  2824. },
  2825.  
  2826.  
  2827. _getRecordDetails: function()
  2828. {
  2829. var details;
  2830. switch (this.type) {
  2831. case WebInspector.TimelineModel.RecordType.GCEvent:
  2832. details = WebInspector.UIString("%s collected", Number.bytesToString(this.data["usedHeapSizeDelta"]));
  2833. break;
  2834. case WebInspector.TimelineModel.RecordType.TimerFire:
  2835. details = this._linkifyScriptLocation(this.data["timerId"]);
  2836. break;
  2837. case WebInspector.TimelineModel.RecordType.FunctionCall:
  2838. details = this._linkifyScriptLocation();
  2839. break;
  2840. case WebInspector.TimelineModel.RecordType.FireAnimationFrame:
  2841. details = this._linkifyScriptLocation(this.data["id"]);
  2842. break;
  2843. case WebInspector.TimelineModel.RecordType.EventDispatch:
  2844. details = this.data ? this.data["type"] : null;
  2845. break;
  2846. case WebInspector.TimelineModel.RecordType.Paint:
  2847. details = this.data["width"] + "\u2009\u00d7\u2009" + this.data["height"];
  2848. break;
  2849. case WebInspector.TimelineModel.RecordType.DecodeImage:
  2850. details = this.data["imageType"];
  2851. break;
  2852. case WebInspector.TimelineModel.RecordType.ResizeImage:
  2853. details = this.data["cached"] ? WebInspector.UIString("cached") : WebInspector.UIString("non-cached");
  2854. break;
  2855. case WebInspector.TimelineModel.RecordType.TimerInstall:
  2856. case WebInspector.TimelineModel.RecordType.TimerRemove:
  2857. details = this._linkifyTopCallFrame(this.data["timerId"]);
  2858. break;
  2859. case WebInspector.TimelineModel.RecordType.RequestAnimationFrame:
  2860. case WebInspector.TimelineModel.RecordType.CancelAnimationFrame:
  2861. details = this._linkifyTopCallFrame(this.data["id"]);
  2862. break;
  2863. case WebInspector.TimelineModel.RecordType.ParseHTML:
  2864. case WebInspector.TimelineModel.RecordType.RecalculateStyles:
  2865. details = this._linkifyTopCallFrame();
  2866. break;
  2867. case WebInspector.TimelineModel.RecordType.EvaluateScript:
  2868. details = this.url ? this._linkifyLocation(this.url, this.data["lineNumber"], 0) : null;
  2869. break;
  2870. case WebInspector.TimelineModel.RecordType.XHRReadyStateChange:
  2871. case WebInspector.TimelineModel.RecordType.XHRLoad:
  2872. case WebInspector.TimelineModel.RecordType.ScheduleResourceRequest:
  2873. case WebInspector.TimelineModel.RecordType.ResourceSendRequest:
  2874. case WebInspector.TimelineModel.RecordType.ResourceReceivedData:
  2875. case WebInspector.TimelineModel.RecordType.ResourceReceiveResponse:
  2876. case WebInspector.TimelineModel.RecordType.ResourceFinish:
  2877. details = WebInspector.displayNameForURL(this.url);
  2878. break;
  2879. case WebInspector.TimelineModel.RecordType.Time:
  2880. case WebInspector.TimelineModel.RecordType.TimeEnd:
  2881. case WebInspector.TimelineModel.RecordType.TimeStamp:
  2882. details = this.data["message"];
  2883. break;
  2884. default:
  2885. details = this._linkifyScriptLocation() || this._linkifyTopCallFrame() || null;
  2886. break;
  2887. }
  2888.  
  2889. if (typeof details === "string")
  2890. return this._createSpanWithText(details);
  2891.  
  2892. return details ? details : null;
  2893. },
  2894.  
  2895.  
  2896. _linkifyLocation: function(url, lineNumber, columnNumber)
  2897. {
  2898.  
  2899. columnNumber = columnNumber ? columnNumber - 1 : 0;
  2900. return this._linkifier.linkifyLocation(url, lineNumber - 1, columnNumber, "timeline-details");
  2901. },
  2902.  
  2903. _linkifyCallFrame: function(callFrame)
  2904. {
  2905. return this._linkifyLocation(callFrame.url, callFrame.lineNumber, callFrame.columnNumber);
  2906. },
  2907.  
  2908.  
  2909. _linkifyTopCallFrame: function(defaultValue)
  2910. {
  2911. if (this.stackTrace)
  2912. return this._linkifyCallFrame(this.stackTrace[0]);
  2913. if (this.callSiteStackTrace)
  2914. return this._linkifyCallFrame(this.callSiteStackTrace[0]);
  2915. return defaultValue;
  2916. },
  2917.  
  2918.  
  2919. _linkifyScriptLocation: function(defaultValue)
  2920. {
  2921. return this.scriptName ? this._linkifyLocation(this.scriptName, this.scriptLine, 0) : defaultValue;
  2922. },
  2923.  
  2924. calculateAggregatedStats: function(categories)
  2925. {
  2926. this._aggregatedStats = {};
  2927. for (var category in categories)
  2928. this._aggregatedStats[category] = 0;
  2929. this._cpuTime = this._selfTime;
  2930.  
  2931. for (var index = this._children.length; index; --index) {
  2932. var child = this._children[index - 1];
  2933. for (var category in categories)
  2934. this._aggregatedStats[category] += child._aggregatedStats[category];
  2935. }
  2936. for (var category in this._aggregatedStats)
  2937. this._cpuTime += this._aggregatedStats[category];
  2938. this._aggregatedStats[this.category.name] += this._selfTime;
  2939. },
  2940.  
  2941. get aggregatedStats()
  2942. {
  2943. return this._aggregatedStats;
  2944. },
  2945.  
  2946. setHasWarning: function()
  2947. {
  2948. this.hasWarning = true;
  2949. for (var parent = this.parent; parent && !parent.childHasWarning; parent = parent.parent)
  2950. parent.childHasWarning = true;
  2951. }
  2952. }
  2953.  
  2954.  
  2955. WebInspector.TimelinePresentationModel._generateAggregatedInfo = function(aggregatedStats)
  2956. {
  2957. var cell = document.createElement("span");
  2958. cell.className = "timeline-aggregated-info";
  2959. for (var index in aggregatedStats) {
  2960. var label = document.createElement("div");
  2961. label.className = "timeline-aggregated-category timeline-" + index;
  2962. cell.appendChild(label);
  2963. var text = document.createElement("span");
  2964. text.textContent = Number.secondsToString(aggregatedStats[index], true);
  2965. cell.appendChild(text);
  2966. }
  2967. return cell;
  2968. }
  2969.  
  2970.  
  2971. WebInspector.TimelinePresentationModel.PopupContentHelper = function(title)
  2972. {
  2973. this._contentTable = document.createElement("table");
  2974. var titleCell = this._createCell(WebInspector.UIString("%s - Details", title), "timeline-details-title");
  2975. titleCell.colSpan = 2;
  2976. var titleRow = document.createElement("tr");
  2977. titleRow.appendChild(titleCell);
  2978. this._contentTable.appendChild(titleRow);
  2979. }
  2980.  
  2981. WebInspector.TimelinePresentationModel.PopupContentHelper.prototype = {
  2982.  
  2983. _createCell: function(content, styleName)
  2984. {
  2985. var text = document.createElement("label");
  2986. text.appendChild(document.createTextNode(content));
  2987. var cell = document.createElement("td");
  2988. cell.className = "timeline-details";
  2989. if (styleName)
  2990. cell.className += " " + styleName;
  2991. cell.textContent = content;
  2992. return cell;
  2993. },
  2994.  
  2995. _appendTextRow: function(title, content)
  2996. {
  2997. var row = document.createElement("tr");
  2998. row.appendChild(this._createCell(title, "timeline-details-row-title"));
  2999. row.appendChild(this._createCell(content, "timeline-details-row-data"));
  3000. this._contentTable.appendChild(row);
  3001. },
  3002.  
  3003.  
  3004. _appendElementRow: function(title, content, titleStyle)
  3005. {
  3006. var row = document.createElement("tr");
  3007. var titleCell = this._createCell(title, "timeline-details-row-title");
  3008. if (titleStyle)
  3009. titleCell.addStyleClass(titleStyle);
  3010. row.appendChild(titleCell);
  3011. var cell = document.createElement("td");
  3012. cell.className = "timeline-details";
  3013. cell.appendChild(content);
  3014. row.appendChild(cell);
  3015. this._contentTable.appendChild(row);
  3016. },
  3017.  
  3018. _appendStackTrace: function(title, stackTrace, callFrameLinkifier)
  3019. {
  3020. this._appendTextRow("", "");
  3021. var framesTable = document.createElement("table");
  3022. for (var i = 0; i < stackTrace.length; ++i) {
  3023. var stackFrame = stackTrace[i];
  3024. var row = document.createElement("tr");
  3025. row.className = "timeline-details";
  3026. row.appendChild(this._createCell(stackFrame.functionName ? stackFrame.functionName : WebInspector.UIString("(anonymous function)"), "timeline-function-name"));
  3027. row.appendChild(this._createCell(" @ "));
  3028. var linkCell = document.createElement("td");
  3029. var urlElement = callFrameLinkifier(stackFrame);
  3030. linkCell.appendChild(urlElement);
  3031. row.appendChild(linkCell);
  3032. framesTable.appendChild(row);
  3033. }
  3034. this._appendElementRow(title, framesTable, "timeline-stacktrace-title");
  3035. }
  3036. }
  3037.  
  3038. WebInspector.TimelinePresentationModel.generatePopupContentForFrame = function(frame)
  3039. {
  3040. var contentHelper = new WebInspector.TimelinePresentationModel.PopupContentHelper(WebInspector.UIString("Frame"));
  3041. var durationInSeconds = frame.endTime - frame.startTime;
  3042. var durationText = WebInspector.UIString("%s (at %s)", Number.secondsToString(frame.endTime - frame.startTime, true),
  3043. Number.secondsToString(frame.startTimeOffset, true));
  3044. contentHelper._appendTextRow(WebInspector.UIString("Duration"), durationText);
  3045. contentHelper._appendTextRow(WebInspector.UIString("FPS"), Math.floor(1 / durationInSeconds));
  3046. contentHelper._appendTextRow(WebInspector.UIString("CPU time"), Number.secondsToString(frame.cpuTime, true));
  3047. contentHelper._appendElementRow(WebInspector.UIString("Aggregated Time"),
  3048. WebInspector.TimelinePresentationModel._generateAggregatedInfo(frame.timeByCategory));
  3049.  
  3050. return contentHelper._contentTable;
  3051. }
  3052.  
  3053.  
  3054. WebInspector.TimelinePresentationModel.generatePopupContentForFrameStatistics = function(statistics)
  3055. {
  3056.  
  3057. function formatTimeAndFPS(time)
  3058. {
  3059. return WebInspector.UIString("%s (%.0f FPS)", Number.secondsToString(time, true), 1 / time);
  3060. }
  3061.  
  3062. var contentHelper = new WebInspector.TimelinePresentationModel.PopupContentHelper(WebInspector.UIString("Selected Range"));
  3063.  
  3064. contentHelper._appendTextRow(WebInspector.UIString("Selected range"), WebInspector.UIString("%s\u2013%s (%d frames)",
  3065. Number.secondsToString(statistics.startOffset, true), Number.secondsToString(statistics.endOffset, true), statistics.frameCount));
  3066. contentHelper._appendTextRow(WebInspector.UIString("Minimum Time"), formatTimeAndFPS(statistics.minDuration));
  3067. contentHelper._appendTextRow(WebInspector.UIString("Average Time"), formatTimeAndFPS(statistics.average));
  3068. contentHelper._appendTextRow(WebInspector.UIString("Maximum Time"), formatTimeAndFPS(statistics.maxDuration));
  3069. contentHelper._appendTextRow(WebInspector.UIString("Standard Deviation"), Number.secondsToString(statistics.stddev, true));
  3070. contentHelper._appendElementRow(WebInspector.UIString("Time by category"),
  3071. WebInspector.TimelinePresentationModel._generateAggregatedInfo(statistics.timeByCategory));
  3072.  
  3073. return contentHelper._contentTable;
  3074. }
  3075.  
  3076.  
  3077. WebInspector.TimelinePresentationModel.createFillStyle = function(context, width, height, color0, color1, color2)
  3078. {
  3079. var gradient = context.createLinearGradient(0, 0, width, height);
  3080. gradient.addColorStop(0, color0);
  3081. gradient.addColorStop(0.25, color1);
  3082. gradient.addColorStop(0.75, color1);
  3083. gradient.addColorStop(1, color2);
  3084. return gradient;
  3085. }
  3086.  
  3087.  
  3088. WebInspector.TimelinePresentationModel.createFillStyleForCategory = function(context, width, height, category)
  3089. {
  3090. return WebInspector.TimelinePresentationModel.createFillStyle(context, width, height, category.fillColorStop0, category.fillColorStop1, category.borderColor);
  3091. }
  3092.  
  3093.  
  3094. WebInspector.TimelinePresentationModel.createStyleRuleForCategory = function(category)
  3095. {
  3096. var selector = ".timeline-category-" + category.name + " .timeline-graph-bar, " +
  3097. ".timeline-category-statusbar-item.timeline-category-" + category.name + " .timeline-category-checkbox, " +
  3098. ".popover .timeline-" + category.name + ", " +
  3099. ".timeline-category-" + category.name + " .timeline-tree-icon"
  3100.  
  3101. return selector + " { background-image: -webkit-linear-gradient(" +
  3102. category.fillColorStop0 + ", " + category.fillColorStop1 + " 25%, " + category.fillColorStop1 + " 75%, " + category.borderColor + ");" +
  3103. " border-color: " + category.borderColor +
  3104. "}";
  3105. }
  3106.  
  3107.  
  3108. WebInspector.TimelinePresentationModel.Filter = function()
  3109. {
  3110. }
  3111.  
  3112. WebInspector.TimelinePresentationModel.Filter.prototype = {
  3113.  
  3114. accept: function(record) { return false; }
  3115. }
  3116.  
  3117.  
  3118. WebInspector.TimelineCategory = function(name, title, overviewStripGroupIndex, borderColor, fillColorStop0, fillColorStop1)
  3119. {
  3120. this.name = name;
  3121. this.title = title;
  3122. this.overviewStripGroupIndex = overviewStripGroupIndex;
  3123. this.borderColor = borderColor;
  3124. this.fillColorStop0 = fillColorStop0;
  3125. this.fillColorStop1 = fillColorStop1;
  3126. this.hidden = false;
  3127. }
  3128.  
  3129. WebInspector.TimelineCategory.Events = {
  3130. VisibilityChanged: "VisibilityChanged"
  3131. };
  3132.  
  3133. WebInspector.TimelineCategory.prototype = {
  3134.  
  3135. get hidden()
  3136. {
  3137. return this._hidden;
  3138. },
  3139.  
  3140. set hidden(hidden)
  3141. {
  3142. this._hidden = hidden;
  3143. this.dispatchEventToListeners(WebInspector.TimelineCategory.Events.VisibilityChanged, this);
  3144. },
  3145.  
  3146. __proto__: WebInspector.Object.prototype
  3147. }
  3148. ;
  3149.  
  3150.  
  3151.  
  3152. WebInspector.TimelineFrameController = function(model, overviewPane, presentationModel)
  3153. {
  3154. this._lastFrame = null;
  3155. this._model = model;
  3156. this._overviewPane = overviewPane;
  3157. this._presentationModel = presentationModel;
  3158. this._model.addEventListener(WebInspector.TimelineModel.Events.RecordAdded, this._onRecordAdded, this);
  3159. this._model.addEventListener(WebInspector.TimelineModel.Events.RecordsCleared, this._onRecordsCleared, this);
  3160.  
  3161. var records = model.records;
  3162. for (var i = 0; i < records.length; ++i)
  3163. this._addRecord(records[i]);
  3164. }
  3165.  
  3166. WebInspector.TimelineFrameController.prototype = {
  3167. _onRecordAdded: function(event)
  3168. {
  3169. this._addRecord(event.data);
  3170. },
  3171.  
  3172. _onRecordsCleared: function()
  3173. {
  3174. this._lastFrame = null;
  3175. },
  3176.  
  3177. _addRecord: function(record)
  3178. {
  3179. var records;
  3180. if (record.type === WebInspector.TimelineModel.RecordType.Program)
  3181. records = record["children"] || [];
  3182. else
  3183. records = [record];
  3184. records.forEach(this._innerAddRecord, this);
  3185. },
  3186.  
  3187. _innerAddRecord: function(record)
  3188. {
  3189. if (record.type === WebInspector.TimelineModel.RecordType.BeginFrame && this._lastFrame)
  3190. this._flushFrame(record);
  3191. else {
  3192. if (!this._lastFrame)
  3193. this._lastFrame = this._createFrame(record);
  3194. WebInspector.TimelineModel.aggregateTimeForRecord(this._lastFrame.timeByCategory, record);
  3195. this._lastFrame.cpuTime += WebInspector.TimelineModel.durationInSeconds(record);
  3196. }
  3197. },
  3198.  
  3199. _flushFrame: function(record)
  3200. {
  3201. this._lastFrame.endTime = WebInspector.TimelineModel.startTimeInSeconds(record);
  3202. this._lastFrame.duration = this._lastFrame.endTime - this._lastFrame.startTime;
  3203. this._overviewPane.addFrame(this._lastFrame);
  3204. this._presentationModel.addFrame(this._lastFrame);
  3205. this._lastFrame = this._createFrame(record);
  3206. },
  3207.  
  3208. _createFrame: function(record)
  3209. {
  3210. var frame = new WebInspector.TimelineFrame();
  3211. frame.startTime = WebInspector.TimelineModel.startTimeInSeconds(record);
  3212. frame.startTimeOffset = this._model.recordOffsetInSeconds(record);
  3213. return frame;
  3214. },
  3215.  
  3216. dispose: function()
  3217. {
  3218. this._model.removeEventListener(WebInspector.TimelineModel.Events.RecordAdded, this._onRecordAdded, this);
  3219. this._model.removeEventListener(WebInspector.TimelineModel.Events.RecordsCleared, this._onRecordsCleared, this);
  3220. }
  3221. }
  3222.  
  3223.  
  3224. WebInspector.FrameStatistics = function(frames)
  3225. {
  3226. this.frameCount = frames.length;
  3227. this.minDuration = Infinity;
  3228. this.maxDuration = 0;
  3229. this.timeByCategory = {};
  3230. this.startOffset = frames[0].startTimeOffset;
  3231. var lastFrame = frames[this.frameCount - 1];
  3232. this.endOffset = lastFrame.startTimeOffset + lastFrame.duration;
  3233.  
  3234. var totalDuration = 0;
  3235. var sumOfSquares = 0;
  3236. for (var i = 0; i < this.frameCount; ++i) {
  3237. var duration = frames[i].duration;
  3238. totalDuration += duration;
  3239. sumOfSquares += duration * duration;
  3240. this.minDuration = Math.min(this.minDuration, duration);
  3241. this.maxDuration = Math.max(this.maxDuration, duration);
  3242. WebInspector.TimelineModel.aggregateTimeByCategory(this.timeByCategory, frames[i].timeByCategory);
  3243. }
  3244. this.average = totalDuration / this.frameCount;
  3245. var variance = sumOfSquares / this.frameCount - this.average * this.average;
  3246. this.stddev = Math.sqrt(variance);
  3247. }
  3248.  
  3249.  
  3250. WebInspector.TimelineFrame = function()
  3251. {
  3252. this.timeByCategory = {};
  3253. this.cpuTime = 0;
  3254. }
  3255. ;
  3256.  
  3257.  
  3258. WebInspector.TimelinePanel = function()
  3259. {
  3260. WebInspector.Panel.call(this, "timeline");
  3261. this.registerRequiredCSS("timelinePanel.css");
  3262.  
  3263. this._model = new WebInspector.TimelineModel();
  3264. this._presentationModel = new WebInspector.TimelinePresentationModel();
  3265.  
  3266. this._overviewModeSetting = WebInspector.settings.createSetting("timelineOverviewMode", WebInspector.TimelineOverviewPane.Mode.Events);
  3267. this._glueRecordsSetting = WebInspector.settings.createSetting("timelineGlueRecords", true);
  3268.  
  3269. this._overviewPane = new WebInspector.TimelineOverviewPane(this._model);
  3270. this._overviewPane.addEventListener(WebInspector.TimelineOverviewPane.Events.WindowChanged, this._invalidateAndScheduleRefresh.bind(this, false));
  3271. this._overviewPane.addEventListener(WebInspector.TimelineOverviewPane.Events.ModeChanged, this._overviewModeChanged, this);
  3272. this._overviewPane.show(this.element);
  3273.  
  3274. this.element.addEventListener("contextmenu", this._contextMenu.bind(this), false);
  3275. this.element.tabIndex = 0;
  3276.  
  3277. this._sidebarBackgroundElement = document.createElement("div");
  3278. this._sidebarBackgroundElement.className = "sidebar split-view-sidebar-left timeline-sidebar-background";
  3279. this.element.appendChild(this._sidebarBackgroundElement);
  3280.  
  3281. this.createSidebarViewWithTree();
  3282. this.element.appendChild(this.splitView.resizerElement());
  3283.  
  3284. this._containerElement = this.splitView.element;
  3285. this._containerElement.id = "timeline-container";
  3286. this._containerElement.addEventListener("scroll", this._onScroll.bind(this), false);
  3287.  
  3288. this._timelineMemorySplitter = this.element.createChild("div");
  3289. this._timelineMemorySplitter.id = "timeline-memory-splitter";
  3290. WebInspector.installDragHandle(this._timelineMemorySplitter, this._startSplitterDragging.bind(this), this._splitterDragging.bind(this), this._endSplitterDragging.bind(this), "ns-resize");
  3291. this._timelineMemorySplitter.addStyleClass("hidden");
  3292. this._memoryStatistics = new WebInspector.MemoryStatistics(this, this._model, this.splitView.sidebarWidth());
  3293. WebInspector.settings.memoryCounterGraphsHeight = WebInspector.settings.createSetting("memoryCounterGraphsHeight", 150);
  3294.  
  3295. var itemsTreeElement = new WebInspector.SidebarSectionTreeElement(WebInspector.UIString("RECORDS"), {}, true);
  3296. this.sidebarTree.appendChild(itemsTreeElement);
  3297.  
  3298. this._sidebarListElement = document.createElement("div");
  3299. this.sidebarElement.appendChild(this._sidebarListElement);
  3300.  
  3301. this._containerContentElement = this.splitView.mainElement;
  3302. this._containerContentElement.id = "resources-container-content";
  3303.  
  3304. this._timelineGrid = new WebInspector.TimelineGrid();
  3305. this._itemsGraphsElement = this._timelineGrid.itemsGraphsElement;
  3306. this._itemsGraphsElement.id = "timeline-graphs";
  3307. this._containerContentElement.appendChild(this._timelineGrid.element);
  3308. this._timelineGrid.gridHeaderElement.id = "timeline-grid-header";
  3309. this._memoryStatistics.setMainTimelineGrid(this._timelineGrid);
  3310. this.element.appendChild(this._timelineGrid.gridHeaderElement);
  3311.  
  3312. this._topGapElement = document.createElement("div");
  3313. this._topGapElement.className = "timeline-gap";
  3314. this._itemsGraphsElement.appendChild(this._topGapElement);
  3315.  
  3316. this._graphRowsElement = document.createElement("div");
  3317. this._itemsGraphsElement.appendChild(this._graphRowsElement);
  3318.  
  3319. this._bottomGapElement = document.createElement("div");
  3320. this._bottomGapElement.className = "timeline-gap";
  3321. this._itemsGraphsElement.appendChild(this._bottomGapElement);
  3322.  
  3323. this._expandElements = document.createElement("div");
  3324. this._expandElements.id = "orphan-expand-elements";
  3325. this._itemsGraphsElement.appendChild(this._expandElements);
  3326.  
  3327. this._calculator = new WebInspector.TimelineCalculator(this._model);
  3328. var shortRecordThresholdTitle = Number.secondsToString(WebInspector.TimelinePresentationModel.shortRecordThreshold);
  3329. this._showShortRecordsTitleText = WebInspector.UIString("Show the records that are shorter than %s", shortRecordThresholdTitle);
  3330. this._hideShortRecordsTitleText = WebInspector.UIString("Hide the records that are shorter than %s", shortRecordThresholdTitle);
  3331. this._createStatusBarItems();
  3332.  
  3333. this._frameMode = false;
  3334. this._boundariesAreValid = true;
  3335. this._scrollTop = 0;
  3336.  
  3337. this._popoverHelper = new WebInspector.PopoverHelper(this.element, this._getPopoverAnchor.bind(this), this._showPopover.bind(this));
  3338. this.element.addEventListener("mousemove", this._mouseMove.bind(this), false);
  3339. this.element.addEventListener("mouseout", this._mouseOut.bind(this), false);
  3340.  
  3341.  
  3342. this.toggleFilterButton.toggled = true;
  3343. this._showShortEvents = this.toggleFilterButton.toggled;
  3344. this._overviewPane.setShowShortEvents(this._showShortEvents);
  3345.  
  3346. this._timeStampRecords = [];
  3347. this._expandOffset = 15;
  3348.  
  3349. this._headerLineCount = 1;
  3350. this._adjustHeaderHeight();
  3351.  
  3352. this._mainThreadTasks =   ([]);
  3353. this._cpuBarsElement = this._timelineGrid.gridHeaderElement.createChild("div", "timeline-cpu-bars");
  3354. this._mainThreadMonitoringEnabled = Capabilities.timelineCanMonitorMainThread && WebInspector.settings.showCpuOnTimelineRuler.get();
  3355. WebInspector.settings.showCpuOnTimelineRuler.addChangeListener(this._showCpuOnTimelineRulerChanged, this);
  3356.  
  3357. this._createFileSelector();
  3358.  
  3359. this._model.addEventListener(WebInspector.TimelineModel.Events.RecordAdded, this._onTimelineEventRecorded, this);
  3360. this._model.addEventListener(WebInspector.TimelineModel.Events.RecordsCleared, this._onRecordsCleared, this);
  3361.  
  3362. this._registerShortcuts();
  3363.  
  3364. this._allRecordsCount = 0;
  3365.  
  3366. this._presentationModel.addFilter(new WebInspector.TimelineWindowFilter(this._overviewPane));
  3367. this._presentationModel.addFilter(new WebInspector.TimelineCategoryFilter()); 
  3368. this._presentationModel.addFilter(new WebInspector.TimelineIsLongFilter(this));
  3369. }
  3370.  
  3371.  
  3372. WebInspector.TimelinePanel.rowHeight = 18;
  3373.  
  3374. WebInspector.TimelinePanel.prototype = {
  3375. _showCpuOnTimelineRulerChanged: function()
  3376. {
  3377. var mainThreadMonitoringEnabled = WebInspector.settings.showCpuOnTimelineRuler.get();
  3378. if (this._mainThreadMonitoringEnabled !== mainThreadMonitoringEnabled) {
  3379. this._mainThreadMonitoringEnabled = mainThreadMonitoringEnabled;
  3380. this._refreshMainThreadBars();
  3381. }
  3382. },
  3383.  
  3384.  
  3385. _startSplitterDragging: function(event)
  3386. {
  3387. this._dragOffset = this._timelineMemorySplitter.offsetTop + 2 - event.pageY;
  3388. return true;
  3389. },
  3390.  
  3391.  
  3392. _splitterDragging: function(event)
  3393. {
  3394. var top = event.pageY + this._dragOffset
  3395. this._setSplitterPosition(top);
  3396. event.preventDefault();
  3397. },
  3398.  
  3399.  
  3400. _endSplitterDragging: function(event)
  3401. {
  3402. delete this._dragOffset;
  3403. this._memoryStatistics.show();
  3404. WebInspector.settings.memoryCounterGraphsHeight.set(this.splitView.element.offsetHeight);
  3405. },
  3406.  
  3407. _setSplitterPosition: function(top)
  3408. {
  3409. const overviewHeight = 90;
  3410. const sectionMinHeight = 100;
  3411. top = Number.constrain(top, overviewHeight + sectionMinHeight, this.element.offsetHeight - sectionMinHeight);
  3412.  
  3413. this.splitView.element.style.height = (top - overviewHeight) + "px";
  3414. this._timelineMemorySplitter.style.top = (top - 2) + "px";
  3415. this._memoryStatistics.setTopPosition(top);
  3416. this._containerElementHeight = this._containerElement.clientHeight;
  3417. this.onResize();
  3418. },
  3419.  
  3420. get calculator()
  3421. {
  3422. return this._calculator;
  3423. },
  3424.  
  3425. get statusBarItems()
  3426. {
  3427. return this._statusBarButtons.select("element").concat([
  3428. this._miscStatusBarItems,
  3429. this.recordsCounter,
  3430. this.frameStatistics
  3431. ]);
  3432. },
  3433.  
  3434. defaultFocusedElement: function()
  3435. {
  3436. return this.element;
  3437. },
  3438.  
  3439. _createStatusBarItems: function()
  3440. {
  3441. this._statusBarButtons = [];
  3442.  
  3443. this.toggleFilterButton = new WebInspector.StatusBarButton(this._hideShortRecordsTitleText, "timeline-filter-status-bar-item");
  3444. this.toggleFilterButton.addEventListener("click", this._toggleFilterButtonClicked, this);
  3445. this._statusBarButtons.push(this.toggleFilterButton);
  3446.  
  3447. this.toggleTimelineButton = new WebInspector.StatusBarButton(WebInspector.UIString("Record"), "record-profile-status-bar-item");
  3448. this.toggleTimelineButton.addEventListener("click", this._toggleTimelineButtonClicked, this);
  3449. this._statusBarButtons.push(this.toggleTimelineButton);
  3450.  
  3451. this.clearButton = new WebInspector.StatusBarButton(WebInspector.UIString("Clear"), "clear-status-bar-item");
  3452. this.clearButton.addEventListener("click", this._clearPanel, this);
  3453. this._statusBarButtons.push(this.clearButton);
  3454.  
  3455. this.garbageCollectButton = new WebInspector.StatusBarButton(WebInspector.UIString("Collect Garbage"), "garbage-collect-status-bar-item");
  3456. this.garbageCollectButton.addEventListener("click", this._garbageCollectButtonClicked, this);
  3457. this._statusBarButtons.push(this.garbageCollectButton);
  3458.  
  3459. this._glueParentButton = new WebInspector.StatusBarButton(WebInspector.UIString("Glue asynchronous events to causes"), "glue-async-status-bar-item");
  3460. this._glueParentButton.toggled = this._glueRecordsSetting.get();
  3461. this._presentationModel.setGlueRecords(this._glueParentButton.toggled);
  3462. this._glueParentButton.addEventListener("click", this._glueParentButtonClicked, this);
  3463. this._statusBarButtons.push(this._glueParentButton);
  3464.  
  3465. this._miscStatusBarItems = document.createElement("div");
  3466. this._miscStatusBarItems.className = "status-bar-items";
  3467.  
  3468. this._statusBarFilters = this._miscStatusBarItems.createChild("div");
  3469. var categories = WebInspector.TimelinePresentationModel.categories();
  3470. for (var categoryName in categories) {
  3471. var category = categories[categoryName];
  3472. if (category.overviewStripGroupIndex < 0)
  3473. continue;
  3474. this._statusBarFilters.appendChild(this._createTimelineCategoryStatusBarCheckbox(category, this._onCategoryCheckboxClicked.bind(this, category)));
  3475. }
  3476.  
  3477. this.recordsCounter = document.createElement("span");
  3478. this.recordsCounter.className = "timeline-records-stats";
  3479.  
  3480. this.frameStatistics = document.createElement("span");
  3481. this.frameStatistics.className = "timeline-records-stats hidden";
  3482. function getAnchor()
  3483. {
  3484. return this.frameStatistics;
  3485. }
  3486. this._frameStatisticsPopoverHelper = new WebInspector.PopoverHelper(this.frameStatistics, getAnchor.bind(this), this._showFrameStatistics.bind(this));
  3487. },
  3488.  
  3489. _createTimelineCategoryStatusBarCheckbox: function(category, onCheckboxClicked)
  3490. {
  3491. var labelContainer = document.createElement("div");
  3492. labelContainer.addStyleClass("timeline-category-statusbar-item");
  3493. labelContainer.addStyleClass("timeline-category-" + category.name);
  3494. labelContainer.addStyleClass("status-bar-item");
  3495.  
  3496. var label = document.createElement("label");
  3497. var checkElement = document.createElement("input");
  3498. checkElement.type = "checkbox";
  3499. checkElement.className = "timeline-category-checkbox";
  3500. checkElement.checked = true;
  3501. checkElement.addEventListener("click", onCheckboxClicked, false);
  3502. label.appendChild(checkElement);
  3503.  
  3504. var typeElement = document.createElement("span");
  3505. typeElement.className = "type";
  3506. typeElement.textContent = category.title;
  3507. label.appendChild(typeElement);
  3508.  
  3509. labelContainer.appendChild(label);
  3510. return labelContainer;
  3511. },
  3512.  
  3513. _onCategoryCheckboxClicked: function(category, event)
  3514. {
  3515. category.hidden = !event.target.checked;
  3516. this._invalidateAndScheduleRefresh(true);
  3517. },
  3518.  
  3519.  
  3520. _setOperationInProgress: function(indicator)
  3521. {
  3522. this._operationInProgress = !!indicator;
  3523. for (var i = 0; i < this._statusBarButtons.length; ++i)
  3524. this._statusBarButtons[i].setEnabled(!this._operationInProgress);
  3525. this._glueParentButton.setEnabled(!this._operationInProgress && !this._frameController);
  3526. this._miscStatusBarItems.removeChildren();
  3527. this._miscStatusBarItems.appendChild(indicator ? indicator.element : this._statusBarFilters);
  3528. },
  3529.  
  3530. _registerShortcuts: function()
  3531. {
  3532. this.registerShortcuts(WebInspector.TimelinePanelDescriptor.ShortcutKeys.StartStopRecording, this._toggleTimelineButtonClicked.bind(this));
  3533. if (InspectorFrontendHost.canSave())
  3534. this.registerShortcuts(WebInspector.TimelinePanelDescriptor.ShortcutKeys.SaveToFile, this._saveToFile.bind(this));
  3535. this.registerShortcuts(WebInspector.TimelinePanelDescriptor.ShortcutKeys.LoadFromFile, this._fileSelectorElement.click.bind(this._fileSelectorElement));
  3536. },
  3537.  
  3538. _createFileSelector: function()
  3539. {
  3540. if (this._fileSelectorElement)
  3541. this.element.removeChild(this._fileSelectorElement);
  3542.  
  3543. var fileSelectorElement = document.createElement("input");
  3544. fileSelectorElement.type = "file";
  3545. fileSelectorElement.style.zIndex = -1;
  3546. fileSelectorElement.style.position = "absolute";
  3547. fileSelectorElement.onchange = this._loadFromFile.bind(this);
  3548. this.element.appendChild(fileSelectorElement);
  3549. this._fileSelectorElement = fileSelectorElement;
  3550. },
  3551.  
  3552. _contextMenu: function(event)
  3553. {
  3554. var contextMenu = new WebInspector.ContextMenu(event);
  3555. if (InspectorFrontendHost.canSave())
  3556. contextMenu.appendItem(WebInspector.UIString("Save Timeline data\u2026"), this._saveToFile.bind(this), this._operationInProgress);
  3557. contextMenu.appendItem(WebInspector.UIString("Load Timeline data\u2026"), this._fileSelectorElement.click.bind(this._fileSelectorElement), this._operationInProgress);
  3558. contextMenu.show();
  3559. },
  3560.  
  3561. _saveToFile: function()
  3562. {
  3563. if (this._operationInProgress)
  3564. return;
  3565. this._model.saveToFile();
  3566. },
  3567.  
  3568. _loadFromFile: function()
  3569. {
  3570. var progressIndicator = this._prepareToLoadTimeline();
  3571. if (!progressIndicator)
  3572. return;
  3573. this._model.loadFromFile(this._fileSelectorElement.files[0], progressIndicator);
  3574. this._createFileSelector();
  3575. },
  3576.  
  3577.  
  3578. loadFromURL: function(url)
  3579. {
  3580. var progressIndicator = this._prepareToLoadTimeline();
  3581. if (!progressIndicator)
  3582. return;
  3583. this._model.loadFromURL(url, progressIndicator);
  3584. },
  3585.  
  3586.  
  3587. _prepareToLoadTimeline: function()
  3588. {
  3589. if (this._operationInProgress)
  3590. return null;
  3591. if (this.toggleTimelineButton.toggled) {
  3592. this.toggleTimelineButton.toggled = false;
  3593. this._model.stopRecord();
  3594. }
  3595. var progressIndicator = new WebInspector.ProgressIndicator();
  3596. progressIndicator.addEventListener(WebInspector.ProgressIndicator.Events.Done, this._setOperationInProgress.bind(this, null));
  3597. this._setOperationInProgress(progressIndicator);
  3598. return progressIndicator;
  3599. },
  3600.  
  3601. _rootRecord: function()
  3602. {
  3603. return this._presentationModel.rootRecord();
  3604. },
  3605.  
  3606. _updateRecordsCounter: function(recordsInWindowCount)
  3607. {
  3608. this.recordsCounter.textContent = WebInspector.UIString("%d of %d records shown", recordsInWindowCount, this._allRecordsCount);
  3609. },
  3610.  
  3611. _updateFrameStatistics: function(frames)
  3612. {
  3613. if (frames.length) {
  3614. this._lastFrameStatistics = new WebInspector.FrameStatistics(frames);
  3615. var details = WebInspector.UIString("avg: %s, \u03c3: %s",
  3616. Number.secondsToString(this._lastFrameStatistics.average, true), Number.secondsToString(this._lastFrameStatistics.stddev, true));
  3617. } else
  3618. this._lastFrameStatistics = null;
  3619. this.frameStatistics.textContent = WebInspector.UIString("%d of %d frames shown", frames.length, this._presentationModel.frames().length);
  3620. if (details) {
  3621. this.frameStatistics.appendChild(document.createTextNode(" ("));
  3622. this.frameStatistics.createChild("span", "timeline-frames-stats").textContent = details;
  3623. this.frameStatistics.appendChild(document.createTextNode(")"));
  3624. }
  3625. },
  3626.  
  3627.  
  3628. _showFrameStatistics: function(anchor, popover)
  3629. {
  3630. popover.show(WebInspector.TimelinePresentationModel.generatePopupContentForFrameStatistics(this._lastFrameStatistics), anchor);
  3631. },
  3632.  
  3633. _updateEventDividers: function()
  3634. {
  3635. this._timelineGrid.removeEventDividers();
  3636. var clientWidth = this._graphRowsElementWidth;
  3637. var dividers = [];
  3638.  
  3639. for (var i = 0; i < this._timeStampRecords.length; ++i) {
  3640. var record = this._timeStampRecords[i];
  3641. var positions = this._calculator.computeBarGraphWindowPosition(record);
  3642. var dividerPosition = Math.round(positions.left);
  3643. if (dividerPosition < 0 || dividerPosition >= clientWidth || dividers[dividerPosition])
  3644. continue;
  3645. var divider = WebInspector.TimelinePresentationModel.createEventDivider(record.type, record.title);
  3646. divider.style.left = dividerPosition + "px";
  3647. dividers[dividerPosition] = divider;
  3648. }
  3649. this._timelineGrid.addEventDividers(dividers);
  3650. },
  3651.  
  3652. _updateFrameBars: function(frames)
  3653. {
  3654. var clientWidth = this._graphRowsElementWidth;
  3655. if (this._frameContainer)
  3656. this._frameContainer.removeChildren();
  3657. else {
  3658. const frameContainerBorderWidth = 1;
  3659. this._frameContainer = document.createElement("div");
  3660. this._frameContainer.addStyleClass("fill");
  3661. this._frameContainer.addStyleClass("timeline-frame-container");
  3662. this._frameContainer.style.height = this._headerLineCount * WebInspector.TimelinePanel.rowHeight + frameContainerBorderWidth + "px";
  3663. this._frameContainer.addEventListener("dblclick", this._onFrameDoubleClicked.bind(this), false);
  3664. }
  3665.  
  3666. var dividers = [ this._frameContainer ];
  3667.  
  3668. for (var i = 0; i < frames.length; ++i) {
  3669. var frame = frames[i];
  3670. var frameStart = this._calculator.computePosition(frame.startTime);
  3671. var frameEnd = this._calculator.computePosition(frame.endTime);
  3672.  
  3673. var frameStrip = document.createElement("div");
  3674. frameStrip.className = "timeline-frame-strip";
  3675. var actualStart = Math.max(frameStart, 0);
  3676. var width = frameEnd - actualStart;
  3677. frameStrip.style.left = actualStart + "px";
  3678. frameStrip.style.width = width + "px";
  3679. frameStrip._frame = frame;
  3680.  
  3681. const minWidthForFrameInfo = 60;
  3682. if (width > minWidthForFrameInfo)
  3683. frameStrip.textContent = Number.secondsToString(frame.endTime - frame.startTime, true);
  3684.  
  3685. this._frameContainer.appendChild(frameStrip);
  3686.  
  3687. if (actualStart > 0) {
  3688. var frameMarker = WebInspector.TimelinePresentationModel.createEventDivider(WebInspector.TimelineModel.RecordType.BeginFrame);
  3689. frameMarker.style.left = frameStart + "px";
  3690. dividers.push(frameMarker);
  3691. }
  3692. }
  3693. this._timelineGrid.addEventDividers(dividers);
  3694. },
  3695.  
  3696. _onFrameDoubleClicked: function(event)
  3697. {
  3698. var frameBar = event.target.enclosingNodeOrSelfWithClass("timeline-frame-strip");
  3699. if (!frameBar)
  3700. return;
  3701. this._overviewPane.zoomToFrame(frameBar._frame);
  3702. },
  3703.  
  3704. _overviewModeChanged: function(event)
  3705. {
  3706. var mode = event.data;
  3707. var shouldShowMemory = mode === WebInspector.TimelineOverviewPane.Mode.Memory;
  3708. var frameMode = mode === WebInspector.TimelineOverviewPane.Mode.Frames;
  3709. this._overviewModeSetting.set(mode);
  3710. if (frameMode !== this._frameMode) {
  3711. this._frameMode = frameMode;
  3712. this._glueParentButton.setEnabled(!frameMode);
  3713. this._presentationModel.setGlueRecords(this._glueParentButton.toggled && !frameMode);
  3714. this._repopulateRecords();
  3715.  
  3716. if (frameMode) {
  3717. this.element.addStyleClass("timeline-frame-overview");
  3718. this.recordsCounter.addStyleClass("hidden");
  3719. this.frameStatistics.removeStyleClass("hidden");
  3720. this._frameController = new WebInspector.TimelineFrameController(this._model, this._overviewPane, this._presentationModel);
  3721. } else {
  3722. this._frameController.dispose();
  3723. this._frameController = null;
  3724. this.element.removeStyleClass("timeline-frame-overview");
  3725. this.recordsCounter.removeStyleClass("hidden");
  3726. this.frameStatistics.addStyleClass("hidden");
  3727. }
  3728. }
  3729. if (shouldShowMemory === this._memoryStatistics.visible())
  3730. return;
  3731. if (!shouldShowMemory) {
  3732. this._timelineMemorySplitter.addStyleClass("hidden");
  3733. this._memoryStatistics.hide();
  3734. this.splitView.element.style.height = "auto";
  3735. this.splitView.element.style.bottom = "0";
  3736. this.onResize();
  3737. } else {
  3738. this._timelineMemorySplitter.removeStyleClass("hidden");
  3739. this._memoryStatistics.show();
  3740. this.splitView.element.style.bottom = "auto";
  3741. this._setSplitterPosition(WebInspector.settings.memoryCounterGraphsHeight.get());
  3742. }
  3743. },
  3744.  
  3745. _toggleTimelineButtonClicked: function()
  3746. {
  3747. if (this._operationInProgress)
  3748. return;
  3749. if (this.toggleTimelineButton.toggled) {
  3750. this._model.stopRecord();
  3751. this.toggleTimelineButton.title = WebInspector.UIString("Record");
  3752. }
  3753. else {
  3754. this._model.startRecord();
  3755. this.toggleTimelineButton.title = WebInspector.UIString("Stop");
  3756. WebInspector.userMetrics.TimelineStarted.record();
  3757. }
  3758. this.toggleTimelineButton.toggled = !this.toggleTimelineButton.toggled;
  3759. },
  3760.  
  3761. _toggleFilterButtonClicked: function()
  3762. {
  3763. this.toggleFilterButton.toggled = !this.toggleFilterButton.toggled;
  3764. this._showShortEvents = this.toggleFilterButton.toggled;
  3765. this._overviewPane.setShowShortEvents(this._showShortEvents);
  3766. this.toggleFilterButton.element.title = this._showShortEvents ? this._hideShortRecordsTitleText : this._showShortRecordsTitleText;
  3767. this._invalidateAndScheduleRefresh(true);
  3768. },
  3769.  
  3770. _garbageCollectButtonClicked: function()
  3771. {
  3772. ProfilerAgent.collectGarbage();
  3773. },
  3774.  
  3775. _glueParentButtonClicked: function()
  3776. {
  3777. var newValue = !this._glueParentButton.toggled;
  3778. this._glueParentButton.toggled = newValue;
  3779. this._presentationModel.setGlueRecords(newValue);
  3780. this._glueRecordsSetting.set(newValue);
  3781. this._repopulateRecords();
  3782. },
  3783.  
  3784. _repopulateRecords: function()
  3785. {
  3786. this._resetPanel();
  3787. this._automaticallySizeWindow = false;
  3788. var records = this._model.records;
  3789. for (var i = 0; i < records.length; ++i)
  3790. this._innerAddRecordToTimeline(records[i]);
  3791. this._invalidateAndScheduleRefresh(false);
  3792. },
  3793.  
  3794. _onTimelineEventRecorded: function(event)
  3795. {
  3796. if (this._innerAddRecordToTimeline(event.data))
  3797. this._invalidateAndScheduleRefresh(false);
  3798. },
  3799.  
  3800. _innerAddRecordToTimeline: function(record)
  3801. {
  3802. if (record.type === WebInspector.TimelineModel.RecordType.Program) {
  3803. this._mainThreadTasks.push({
  3804. startTime: WebInspector.TimelineModel.startTimeInSeconds(record),
  3805. endTime: WebInspector.TimelineModel.endTimeInSeconds(record)
  3806. });
  3807. }
  3808.  
  3809. var records = this._presentationModel.addRecord(record);
  3810. this._allRecordsCount += records.length;
  3811. var timeStampRecords = this._timeStampRecords;
  3812. var hasVisibleRecords = false;
  3813. var presentationModel = this._presentationModel;
  3814. function processRecord(record)
  3815. {
  3816. if (WebInspector.TimelinePresentationModel.isEventDivider(record))
  3817. timeStampRecords.push(record);
  3818. hasVisibleRecords |= presentationModel.isVisible(record);
  3819. }
  3820. WebInspector.TimelinePresentationModel.forAllRecords(records, processRecord);
  3821.  
  3822. function isAdoptedRecord(record)
  3823. {
  3824. return record.parent !== presentationModel.rootRecord;
  3825. }
  3826.  
  3827. return hasVisibleRecords || records.some(isAdoptedRecord);
  3828. },
  3829.  
  3830. sidebarResized: function(event)
  3831. {
  3832. var width = event.data;
  3833. this._sidebarBackgroundElement.style.width = width + "px";
  3834. this.onResize();
  3835. this._overviewPane.sidebarResized(width);
  3836. this._memoryStatistics.setSidebarWidth(width);
  3837. this._timelineGrid.gridHeaderElement.style.left = width + "px";
  3838. },
  3839.  
  3840. onResize: function()
  3841. {
  3842. this._closeRecordDetails();
  3843. this._scheduleRefresh(false);
  3844. this._graphRowsElementWidth = this._graphRowsElement.offsetWidth;
  3845. this._timelineGrid.gridHeaderElement.style.width = this._itemsGraphsElement.offsetWidth + "px";
  3846. this._containerElementHeight = this._containerElement.clientHeight;
  3847. var minFloatingStatusBarItemsOffset = document.getElementById("panel-status-bar").totalOffsetLeft() + this._statusBarButtons.length * WebInspector.StatusBarButton.width;
  3848. this._miscStatusBarItems.style.left = Math.max(minFloatingStatusBarItemsOffset, this.splitView.sidebarWidth()) + "px";
  3849. },
  3850.  
  3851. _clearPanel: function()
  3852. {
  3853. this._model.reset();
  3854. },
  3855.  
  3856. _onRecordsCleared: function()
  3857. {
  3858. this._resetPanel();
  3859. this._invalidateAndScheduleRefresh(true);
  3860. },
  3861.  
  3862. _resetPanel: function()
  3863. {
  3864. this._presentationModel.reset();
  3865. this._timeStampRecords = [];
  3866. this._boundariesAreValid = false;
  3867. this._adjustScrollPosition(0);
  3868. this._closeRecordDetails();
  3869. this._allRecordsCount = 0;
  3870. this._automaticallySizeWindow = true;
  3871. this._mainThreadTasks = [];
  3872. },
  3873.  
  3874. elementsToRestoreScrollPositionsFor: function()
  3875. {
  3876. return [this._containerElement];
  3877. },
  3878.  
  3879. wasShown: function()
  3880. {
  3881. WebInspector.Panel.prototype.wasShown.call(this);
  3882. if (!WebInspector.TimelinePanel._categoryStylesInitialized) {
  3883. WebInspector.TimelinePanel._categoryStylesInitialized = true;
  3884. this._injectCategoryStyles();
  3885. }
  3886. this._overviewPane.setMode(this._overviewModeSetting.get());
  3887. this._refresh();
  3888. },
  3889.  
  3890. willHide: function()
  3891. {
  3892. this._closeRecordDetails();
  3893. WebInspector.Panel.prototype.willHide.call(this);
  3894. },
  3895.  
  3896. _onScroll: function(event)
  3897. {
  3898. this._closeRecordDetails();
  3899. this._scrollTop = this._containerElement.scrollTop;
  3900. var dividersTop = Math.max(0, this._scrollTop);
  3901. this._timelineGrid.setScrollAndDividerTop(this._scrollTop, dividersTop);
  3902. this._scheduleRefresh(true);
  3903. },
  3904.  
  3905. _invalidateAndScheduleRefresh: function(preserveBoundaries)
  3906. {
  3907. this._presentationModel.invalidateFilteredRecords();
  3908. delete this._searchResults;
  3909. this._scheduleRefresh(preserveBoundaries);
  3910. },
  3911.  
  3912.  
  3913. _scheduleRefresh: function(preserveBoundaries)
  3914. {
  3915. this._closeRecordDetails();
  3916. this._boundariesAreValid &= preserveBoundaries;
  3917.  
  3918. if (!this.isShowing())
  3919. return;
  3920.  
  3921. if (preserveBoundaries)
  3922. this._refresh();
  3923. else {
  3924. if (!this._refreshTimeout)
  3925. this._refreshTimeout = setTimeout(this._refresh.bind(this), 300);
  3926. }
  3927. },
  3928.  
  3929. _refresh: function()
  3930. {
  3931. if (this._refreshTimeout) {
  3932. clearTimeout(this._refreshTimeout);
  3933. delete this._refreshTimeout;
  3934. }
  3935.  
  3936. this._timelinePaddingLeft = !this._overviewPane.windowLeft() ? this._expandOffset : 0;
  3937. this._calculator.setWindow(this._overviewPane.windowStartTime(), this._overviewPane.windowEndTime());
  3938. this._calculator.setDisplayWindow(this._timelinePaddingLeft, this._graphRowsElementWidth);
  3939.  
  3940. var recordsInWindowCount = this._refreshRecords();
  3941. this._updateRecordsCounter(recordsInWindowCount);
  3942. if (!this._boundariesAreValid) {
  3943. this._updateEventDividers();
  3944. var frames = this._frameController && this._presentationModel.filteredFrames(this._overviewPane.windowStartTime(), this._overviewPane.windowEndTime());
  3945. if (frames) {
  3946. this._updateFrameStatistics(frames);
  3947. const maxFramesForFrameBars = 30;
  3948. if  (frames.length && frames.length < maxFramesForFrameBars) {
  3949. this._timelineGrid.removeDividers();
  3950. this._updateFrameBars(frames);
  3951. } else
  3952. this._timelineGrid.updateDividers(this._calculator);
  3953. } else
  3954. this._timelineGrid.updateDividers(this._calculator);
  3955. if (this._mainThreadMonitoringEnabled)
  3956. this._refreshMainThreadBars();
  3957. }
  3958. if (this._memoryStatistics.visible())
  3959. this._memoryStatistics.refresh();
  3960. this._boundariesAreValid = true;
  3961. },
  3962.  
  3963. revealRecordAt: function(time)
  3964. {
  3965. var recordToReveal;
  3966. function findRecordToReveal(record)
  3967. {
  3968. if (record.containsTime(time)) {
  3969. recordToReveal = record;
  3970. return true;
  3971. }
  3972.  
  3973. if (!recordToReveal || record.endTime < time && recordToReveal.endTime < record.endTime)
  3974. recordToReveal = record;
  3975. return false;
  3976. }
  3977. WebInspector.TimelinePresentationModel.forAllRecords(this._presentationModel.rootRecord().children, null, findRecordToReveal);
  3978.  
  3979.  
  3980. if (!recordToReveal) {
  3981. this._containerElement.scrollTop = 0;
  3982. return;
  3983. }
  3984.  
  3985. this._revealRecord(recordToReveal);
  3986. },
  3987.  
  3988. _revealRecord: function(recordToReveal)
  3989. {
  3990.  
  3991. var treeUpdated = false;
  3992. for (var parent = recordToReveal.parent; parent !== this._rootRecord(); parent = parent.parent) {
  3993. treeUpdated = treeUpdated || parent.collapsed;
  3994. parent.collapsed = false;
  3995. }
  3996. if (treeUpdated)
  3997. this._invalidateAndScheduleRefresh(true);
  3998.  
  3999. var recordsInWindow = this._presentationModel.filteredRecords();
  4000. var index = recordsInWindow.indexOf(recordToReveal);
  4001. this._containerElement.scrollTop = index * WebInspector.TimelinePanel.rowHeight;
  4002. },
  4003.  
  4004. _refreshRecords: function()
  4005. {
  4006. var recordsInWindow = this._presentationModel.filteredRecords();
  4007.  
  4008.  
  4009. var visibleTop = this._scrollTop;
  4010. var visibleBottom = visibleTop + this._containerElementHeight;
  4011.  
  4012. const rowHeight = WebInspector.TimelinePanel.rowHeight;
  4013.  
  4014.  
  4015. var startIndex = Math.max(0, Math.min(Math.floor(visibleTop / rowHeight) - this._headerLineCount, recordsInWindow.length - 1));
  4016. var endIndex = Math.min(recordsInWindow.length, Math.ceil(visibleBottom / rowHeight));
  4017. var lastVisibleLine = Math.max(0, Math.floor(visibleBottom / rowHeight) - this._headerLineCount);
  4018. if (this._automaticallySizeWindow && recordsInWindow.length > lastVisibleLine) {
  4019. this._automaticallySizeWindow = false;
  4020.  
  4021. var windowStartTime = startIndex ? recordsInWindow[startIndex].startTime : this._model.minimumRecordTime();
  4022. this._overviewPane.setWindowTimes(windowStartTime, recordsInWindow[Math.max(0, lastVisibleLine - 1)].endTime);
  4023. recordsInWindow = this._presentationModel.filteredRecords();
  4024. endIndex = Math.min(recordsInWindow.length, lastVisibleLine);
  4025. }
  4026.  
  4027.  
  4028. const top = (startIndex * rowHeight) + "px";
  4029. this._topGapElement.style.height = top;
  4030. this.sidebarElement.style.top = top;
  4031. this._bottomGapElement.style.height = (recordsInWindow.length - endIndex) * rowHeight + "px";
  4032.  
  4033.  
  4034. var listRowElement = this._sidebarListElement.firstChild;
  4035. var width = this._graphRowsElementWidth;
  4036. this._itemsGraphsElement.removeChild(this._graphRowsElement);
  4037. var graphRowElement = this._graphRowsElement.firstChild;
  4038. var scheduleRefreshCallback = this._invalidateAndScheduleRefresh.bind(this, true);
  4039. this._itemsGraphsElement.removeChild(this._expandElements);
  4040. this._expandElements.removeChildren();
  4041.  
  4042. for (var i = 0; i < endIndex; ++i) {
  4043. var record = recordsInWindow[i];
  4044. var isEven = !(i % 2);
  4045.  
  4046. if (i < startIndex) {
  4047. var lastChildIndex = i + record.visibleChildrenCount;
  4048. if (lastChildIndex >= startIndex && lastChildIndex < endIndex) {
  4049. var expandElement = new WebInspector.TimelineExpandableElement(this._expandElements);
  4050. var positions = this._calculator.computeBarGraphWindowPosition(record);
  4051. expandElement._update(record, i, positions.left - this._expandOffset, positions.width);
  4052. }
  4053. } else {
  4054. if (!listRowElement) {
  4055. listRowElement = new WebInspector.TimelineRecordListRow().element;
  4056. this._sidebarListElement.appendChild(listRowElement);
  4057. }
  4058. if (!graphRowElement) {
  4059. graphRowElement = new WebInspector.TimelineRecordGraphRow(this._itemsGraphsElement, scheduleRefreshCallback).element;
  4060. this._graphRowsElement.appendChild(graphRowElement);
  4061. }
  4062.  
  4063. listRowElement.row.update(record, isEven, visibleTop);
  4064. graphRowElement.row.update(record, isEven, this._calculator, this._expandOffset, i);
  4065.  
  4066. listRowElement = listRowElement.nextSibling;
  4067. graphRowElement = graphRowElement.nextSibling;
  4068. }
  4069. }
  4070.  
  4071.  
  4072. while (listRowElement) {
  4073. var nextElement = listRowElement.nextSibling;
  4074. listRowElement.row.dispose();
  4075. listRowElement = nextElement;
  4076. }
  4077. while (graphRowElement) {
  4078. var nextElement = graphRowElement.nextSibling;
  4079. graphRowElement.row.dispose();
  4080. graphRowElement = nextElement;
  4081. }
  4082.  
  4083. this._itemsGraphsElement.insertBefore(this._graphRowsElement, this._bottomGapElement);
  4084. this._itemsGraphsElement.appendChild(this._expandElements);
  4085. this._adjustScrollPosition((recordsInWindow.length + this._headerLineCount) * rowHeight);
  4086. this._updateSearchHighlight(false);
  4087.  
  4088. return recordsInWindow.length;
  4089. },
  4090.  
  4091. _refreshMainThreadBars: function()
  4092. {
  4093. const barOffset = 3;
  4094. const minGap = 3;
  4095.  
  4096. var minWidth = WebInspector.TimelineCalculator._minWidth;
  4097. var widthAdjustment = minWidth / 2;
  4098.  
  4099. var width = this._graphRowsElementWidth;
  4100. var boundarySpan = this._overviewPane.windowEndTime() - this._overviewPane.windowStartTime();
  4101. var scale = boundarySpan / (width - minWidth - this._timelinePaddingLeft);
  4102. var startTime = this._overviewPane.windowStartTime() - this._timelinePaddingLeft * scale;
  4103. var endTime = startTime + width * scale;
  4104.  
  4105. var tasks = this._mainThreadMonitoringEnabled ? this._mainThreadTasks : [];
  4106.  
  4107. function compareEndTime(value, task)
  4108. {
  4109. return value < task.endTime ? -1 : 1;
  4110. }
  4111.  
  4112. var taskIndex = insertionIndexForObjectInListSortedByFunction(startTime, tasks, compareEndTime);
  4113.  
  4114. var container = this._cpuBarsElement;
  4115. var element = container.firstChild;
  4116. var lastElement;
  4117. var lastLeft;
  4118. var lastRight;
  4119.  
  4120. while (taskIndex < tasks.length) {
  4121. var task = tasks[taskIndex];
  4122. if (task.startTime > endTime)
  4123. break;
  4124. taskIndex++;
  4125.  
  4126. var left = Math.max(0, this._calculator.computePosition(task.startTime) + barOffset - widthAdjustment);
  4127. var right = Math.min(width, this._calculator.computePosition(task.endTime) + barOffset + widthAdjustment);
  4128.  
  4129. if (lastElement) {
  4130. var gap = Math.floor(left) - Math.ceil(lastRight);
  4131. if (gap < minGap) {
  4132. lastRight = right;
  4133. lastElement._tasksInfo.lastTaskIndex = taskIndex;
  4134. continue;
  4135. }
  4136. lastElement.style.width = (lastRight - lastLeft) + "px";
  4137. }
  4138.  
  4139. if (!element)
  4140. element = container.createChild("div", "timeline-graph-bar");
  4141.  
  4142. element.style.left = left + "px";
  4143. element._tasksInfo = {tasks: tasks, firstTaskIndex: taskIndex, lastTaskIndex: taskIndex};
  4144. lastLeft = left;
  4145. lastRight = right;
  4146.  
  4147. lastElement = element;
  4148. element = element.nextSibling;
  4149. }
  4150.  
  4151. if (lastElement)
  4152. lastElement.style.width = (lastRight - lastLeft) + "px";
  4153.  
  4154. while (element) {
  4155. var nextElement = element.nextSibling;
  4156. element._tasksInfo = null;
  4157. container.removeChild(element);
  4158. element = nextElement;
  4159. }
  4160. },
  4161.  
  4162. _adjustHeaderHeight: function()
  4163. {
  4164. const headerBorderWidth = 1;
  4165. const headerMargin = 2;
  4166.  
  4167. var headerHeight = this._headerLineCount * WebInspector.TimelinePanel.rowHeight;
  4168. this.sidebarElement.firstChild.style.height = headerHeight + "px";
  4169. this._timelineGrid.dividersLabelBarElement.style.height = headerHeight + headerMargin + "px";
  4170. this._itemsGraphsElement.style.top = headerHeight + headerBorderWidth + "px";
  4171. },
  4172.  
  4173. _adjustScrollPosition: function(totalHeight)
  4174. {
  4175.  
  4176. if ((this._scrollTop + this._containerElementHeight) > totalHeight + 1)
  4177. this._containerElement.scrollTop = (totalHeight - this._containerElement.offsetHeight);
  4178. },
  4179.  
  4180. _getPopoverAnchor: function(element)
  4181. {
  4182. return element.enclosingNodeOrSelfWithClass("timeline-graph-bar") ||
  4183. element.enclosingNodeOrSelfWithClass("timeline-tree-item") ||
  4184. element.enclosingNodeOrSelfWithClass("timeline-frame-strip");
  4185. },
  4186.  
  4187. _mouseOut: function(e)
  4188. {
  4189. this._hideRectHighlight();
  4190. },
  4191.  
  4192. _mouseMove: function(e)
  4193. {
  4194. var anchor = this._getPopoverAnchor(e.target);
  4195.  
  4196. const recordType = WebInspector.TimelineModel.RecordType;
  4197. if (anchor && anchor.row && (anchor.row._record.type === recordType.Paint || anchor.row._record.type === recordType.Layout))
  4198. this._highlightRect(anchor.row._record);
  4199. else
  4200. this._hideRectHighlight();
  4201. },
  4202.  
  4203. _highlightRect: function(record)
  4204. {
  4205. if (this._highlightedRect === record.data)
  4206. return;
  4207. this._highlightedRect = record.data;
  4208. DOMAgent.highlightRect(this._highlightedRect.x, this._highlightedRect.y, this._highlightedRect.width, this._highlightedRect.height, WebInspector.Color.PageHighlight.Content.toProtocolRGBA(), WebInspector.Color.PageHighlight.ContentOutline.toProtocolRGBA());
  4209. },
  4210.  
  4211. _hideRectHighlight: function()
  4212. {
  4213. if (this._highlightedRect) {
  4214. delete this._highlightedRect;
  4215. DOMAgent.hideHighlight();
  4216. }
  4217. },
  4218.  
  4219.  
  4220. _showPopover: function(anchor, popover)
  4221. {
  4222. if (anchor.hasStyleClass("timeline-frame-strip")) {
  4223. var frame = anchor._frame;
  4224. popover.show(WebInspector.TimelinePresentationModel.generatePopupContentForFrame(frame), anchor);
  4225. } else {
  4226. if (anchor.row && anchor.row._record)
  4227. anchor.row._record.generatePopupContent(showCallback);
  4228. else if (anchor._tasksInfo)
  4229. popover.show(this._presentationModel.generateMainThreadBarPopupContent(anchor._tasksInfo), anchor);
  4230. }
  4231.  
  4232. function showCallback(popupContent)
  4233. {
  4234. popover.show(popupContent, anchor);
  4235. }
  4236. },
  4237.  
  4238. _closeRecordDetails: function()
  4239. {
  4240. this._popoverHelper.hidePopover();
  4241. },
  4242.  
  4243. _injectCategoryStyles: function()
  4244. {
  4245. var style = document.createElement("style");
  4246. var categories = WebInspector.TimelinePresentationModel.categories();
  4247.  
  4248. style.textContent = Object.values(categories).map(WebInspector.TimelinePresentationModel.createStyleRuleForCategory).join("\n");
  4249. document.head.appendChild(style);
  4250. },
  4251.  
  4252. jumpToNextSearchResult: function()
  4253. {
  4254. this._jumpToAdjacentRecord(1);
  4255. },
  4256.  
  4257. jumpToPreviousSearchResult: function()
  4258. {
  4259. this._jumpToAdjacentRecord(-1);
  4260. },
  4261.  
  4262. _jumpToAdjacentRecord: function(offset)
  4263. {
  4264. if (!this._searchResults || !this._searchResults.length || !this._selectedSearchResult)
  4265. return;
  4266. var index = this._searchResults.indexOf(this._selectedSearchResult);
  4267. index = (index + offset + this._searchResults.length) % this._searchResults.length;
  4268. this._selectSearchResult(index);
  4269. this._highlightSelectedSearchResult(true);
  4270. },
  4271.  
  4272. _selectSearchResult: function(index)
  4273. {
  4274. this._selectedSearchResult = this._searchResults[index];
  4275. WebInspector.searchController.updateCurrentMatchIndex(index, this);
  4276. },
  4277.  
  4278. _highlightSelectedSearchResult: function(revealRecord)
  4279. {
  4280. this._clearHighlight();
  4281. if (this._searchFilter)
  4282. return;
  4283.  
  4284. var record = this._selectedSearchResult;
  4285. if (!record)
  4286. return;
  4287.  
  4288. for (var element = this._sidebarListElement.firstChild; element; element = element.nextSibling) {
  4289. if (element.row._record === record) {
  4290. element.row.highlight(this._searchRegExp, this._highlightDomChanges);
  4291. return;
  4292. }
  4293. }
  4294.  
  4295. if (revealRecord)
  4296. this._revealRecord(record);
  4297. },
  4298.  
  4299. _clearHighlight: function()
  4300. {
  4301. if (this._highlightDomChanges)
  4302. WebInspector.revertDomChanges(this._highlightDomChanges);
  4303. this._highlightDomChanges = [];
  4304. },
  4305.  
  4306.  
  4307. _updateSearchHighlight: function(revealRecord)
  4308. {
  4309. if (this._searchFilter || !this._searchRegExp) {
  4310. this._clearHighlight();
  4311. return;
  4312. }
  4313.  
  4314. if (!this._searchResults)
  4315. this._updateSearchResults();
  4316.  
  4317. this._highlightSelectedSearchResult(revealRecord);
  4318. },
  4319.  
  4320. _updateSearchResults: function() {
  4321. var searchRegExp = this._searchRegExp;
  4322. if (!searchRegExp)
  4323. return;
  4324.  
  4325. var matches = [];
  4326. var presentationModel = this._presentationModel;
  4327.  
  4328. function processRecord(record)
  4329. {
  4330. if (presentationModel.isVisible(record) && WebInspector.TimelineRecordListRow.testContentMatching(record, searchRegExp))
  4331. matches.push(record);
  4332. return false;
  4333. }
  4334. WebInspector.TimelinePresentationModel.forAllRecords(presentationModel.rootRecord().children, processRecord);
  4335.  
  4336. var matchesCount = matches.length;
  4337. if (matchesCount) {
  4338. this._searchResults = matches;
  4339. WebInspector.searchController.updateSearchMatchesCount(matchesCount, this);
  4340.  
  4341. var selectedIndex = matches.indexOf(this._selectedSearchResult);
  4342. if (selectedIndex === -1)
  4343. selectedIndex = 0;
  4344. this._selectSearchResult(selectedIndex);
  4345. } else {
  4346. WebInspector.searchController.updateSearchMatchesCount(0, this);
  4347. delete this._selectedSearchResult;
  4348. }
  4349. },
  4350.  
  4351. searchCanceled: function()
  4352. {
  4353. this._clearHighlight();
  4354. delete this._searchResults;
  4355. delete this._selectedSearchResult;
  4356. delete this._searchRegExp;
  4357. },
  4358.  
  4359.  
  4360. canFilter: function()
  4361. {
  4362. return true;
  4363. },
  4364.  
  4365. performFilter: function(searchQuery)
  4366. {
  4367. this._presentationModel.removeFilter(this._searchFilter);
  4368. delete this._searchFilter;
  4369. this.searchCanceled();
  4370. if (searchQuery) {
  4371. this._searchFilter = new WebInspector.TimelineSearchFilter(createPlainTextSearchRegex(searchQuery, "i"));
  4372. this._presentationModel.addFilter(this._searchFilter);
  4373. }
  4374. this._invalidateAndScheduleRefresh(true);
  4375. },
  4376.  
  4377. performSearch: function(searchQuery)
  4378. {
  4379. this._searchRegExp = createPlainTextSearchRegex(searchQuery, "i");
  4380. delete this._searchResults;
  4381. this._updateSearchHighlight(true);
  4382. },
  4383.  
  4384. __proto__: WebInspector.Panel.prototype
  4385. }
  4386.  
  4387.  
  4388. WebInspector.TimelineCalculator = function(model)
  4389. {
  4390. this._model = model;
  4391. }
  4392.  
  4393. WebInspector.TimelineCalculator._minWidth = 5;
  4394.  
  4395. WebInspector.TimelineCalculator.prototype = {
  4396.  
  4397. computePosition: function(time)
  4398. {
  4399. return (time - this._minimumBoundary) / this.boundarySpan() * this._workingArea + this.paddingLeft;
  4400. },
  4401.  
  4402. computeBarGraphPercentages: function(record)
  4403. {
  4404. var start = (record.startTime - this._minimumBoundary) / this.boundarySpan() * 100;
  4405. var end = (record.startTime + record.selfTime - this._minimumBoundary) / this.boundarySpan() * 100;
  4406. var endWithChildren = (record.lastChildEndTime - this._minimumBoundary) / this.boundarySpan() * 100;
  4407. var cpuWidth = record.cpuTime / this.boundarySpan() * 100;
  4408. return {start: start, end: end, endWithChildren: endWithChildren, cpuWidth: cpuWidth};
  4409. },
  4410.  
  4411. computeBarGraphWindowPosition: function(record)
  4412. {
  4413. var percentages = this.computeBarGraphPercentages(record);
  4414. var widthAdjustment = 0;
  4415.  
  4416. var left = this.computePosition(record.startTime);
  4417. var width = (percentages.end - percentages.start) / 100 * this._workingArea;
  4418. if (width < WebInspector.TimelineCalculator._minWidth) {
  4419. widthAdjustment = WebInspector.TimelineCalculator._minWidth - width;
  4420. left -= widthAdjustment / 2;
  4421. width += widthAdjustment;
  4422. }
  4423. var widthWithChildren = (percentages.endWithChildren - percentages.start) / 100 * this._workingArea + widthAdjustment;
  4424. var cpuWidth = percentages.cpuWidth / 100 * this._workingArea + widthAdjustment;
  4425. if (percentages.endWithChildren > percentages.end)
  4426. widthWithChildren += widthAdjustment;
  4427. return {left: left, width: width, widthWithChildren: widthWithChildren, cpuWidth: cpuWidth};
  4428. },
  4429.  
  4430. setWindow: function(minimumBoundary, maximumBoundary)
  4431. {
  4432. this._minimumBoundary = minimumBoundary;
  4433. this._maximumBoundary = maximumBoundary;
  4434. },
  4435.  
  4436.  
  4437. setDisplayWindow: function(paddingLeft, clientWidth)
  4438. {
  4439. this._workingArea = clientWidth - WebInspector.TimelineCalculator._minWidth - paddingLeft;
  4440. this.paddingLeft = paddingLeft;
  4441. },
  4442.  
  4443. formatTime: function(value)
  4444. {
  4445. return Number.secondsToString(value + this._minimumBoundary - this._model.minimumRecordTime());
  4446. },
  4447.  
  4448. maximumBoundary: function()
  4449. {
  4450. return this._maximumBoundary;
  4451. },
  4452.  
  4453. minimumBoundary: function()
  4454. {
  4455. return this._minimumBoundary;
  4456. },
  4457.  
  4458. boundarySpan: function()
  4459. {
  4460. return this._maximumBoundary - this._minimumBoundary;
  4461. }
  4462. }
  4463.  
  4464.  
  4465. WebInspector.TimelineRecordListRow = function()
  4466. {
  4467. this.element = document.createElement("div");
  4468. this.element.row = this;
  4469. this.element.style.cursor = "pointer";
  4470. var iconElement = document.createElement("span");
  4471. iconElement.className = "timeline-tree-icon";
  4472. this.element.appendChild(iconElement);
  4473.  
  4474. this._typeElement = document.createElement("span");
  4475. this._typeElement.className = "type";
  4476. this.element.appendChild(this._typeElement);
  4477.  
  4478. var separatorElement = document.createElement("span");
  4479. separatorElement.className = "separator";
  4480. separatorElement.textContent = " ";
  4481.  
  4482. this._dataElement = document.createElement("span");
  4483. this._dataElement.className = "data dimmed";
  4484.  
  4485. this.element.appendChild(separatorElement);
  4486. this.element.appendChild(this._dataElement);
  4487. }
  4488.  
  4489. WebInspector.TimelineRecordListRow.prototype = {
  4490. update: function(record, isEven, offset)
  4491. {
  4492. this._record = record;
  4493. this._offset = offset;
  4494.  
  4495. this.element.className = "timeline-tree-item timeline-category-" + record.category.name;
  4496. if (isEven)
  4497. this.element.addStyleClass("even");
  4498. if (record.hasWarning)
  4499. this.element.addStyleClass("warning");
  4500. else if (record.childHasWarning)
  4501. this.element.addStyleClass("child-warning");
  4502.  
  4503. this._typeElement.textContent = record.title;
  4504.  
  4505. if (this._dataElement.firstChild)
  4506. this._dataElement.removeChildren();
  4507.  
  4508. if (record.detailsNode())
  4509. this._dataElement.appendChild(record.detailsNode());
  4510. },
  4511.  
  4512. highlight: function(regExp, domChanges)
  4513. {
  4514. var matchInfo = this.element.textContent.match(regExp);
  4515. if (matchInfo)
  4516. WebInspector.highlightSearchResult(this.element, matchInfo.index, matchInfo[0].length, domChanges);
  4517. },
  4518.  
  4519. dispose: function()
  4520. {
  4521. this.element.parentElement.removeChild(this.element);
  4522. }
  4523. }
  4524.  
  4525.  
  4526. WebInspector.TimelineRecordListRow.testContentMatching = function(record, regExp)
  4527. {
  4528. var toSearchText = record.title;
  4529. if (record.detailsNode())
  4530. toSearchText += " " + record.detailsNode().textContent;
  4531. return regExp.test(toSearchText);
  4532. }
  4533.  
  4534.  
  4535. WebInspector.TimelineRecordGraphRow = function(graphContainer, scheduleRefresh)
  4536. {
  4537. this.element = document.createElement("div");
  4538. this.element.row = this;
  4539.  
  4540. this._barAreaElement = document.createElement("div");
  4541. this._barAreaElement.className = "timeline-graph-bar-area";
  4542. this.element.appendChild(this._barAreaElement);
  4543.  
  4544. this._barWithChildrenElement = document.createElement("div");
  4545. this._barWithChildrenElement.className = "timeline-graph-bar with-children";
  4546. this._barWithChildrenElement.row = this;
  4547. this._barAreaElement.appendChild(this._barWithChildrenElement);
  4548.  
  4549. this._barCpuElement = document.createElement("div");
  4550. this._barCpuElement.className = "timeline-graph-bar cpu"
  4551. this._barCpuElement.row = this;
  4552. this._barAreaElement.appendChild(this._barCpuElement);
  4553.  
  4554. this._barElement = document.createElement("div");
  4555. this._barElement.className = "timeline-graph-bar";
  4556. this._barElement.row = this;
  4557. this._barAreaElement.appendChild(this._barElement);
  4558.  
  4559. this._expandElement = new WebInspector.TimelineExpandableElement(graphContainer);
  4560. this._expandElement._element.addEventListener("click", this._onClick.bind(this));
  4561.  
  4562. this._scheduleRefresh = scheduleRefresh;
  4563. }
  4564.  
  4565. WebInspector.TimelineRecordGraphRow.prototype = {
  4566. update: function(record, isEven, calculator, expandOffset, index)
  4567. {
  4568. this._record = record;
  4569. this.element.className = "timeline-graph-side timeline-category-" + record.category.name + (isEven ? " even" : "");
  4570. var barPosition = calculator.computeBarGraphWindowPosition(record);
  4571. this._barWithChildrenElement.style.left = barPosition.left + "px";
  4572. this._barWithChildrenElement.style.width = barPosition.widthWithChildren + "px";
  4573. this._barElement.style.left = barPosition.left + "px";
  4574. this._barElement.style.width = barPosition.width + "px";
  4575. this._barCpuElement.style.left = barPosition.left + "px";
  4576. this._barCpuElement.style.width = barPosition.cpuWidth + "px";
  4577. this._expandElement._update(record, index, barPosition.left - expandOffset, barPosition.width);
  4578. },
  4579.  
  4580. _onClick: function(event)
  4581. {
  4582. this._record.collapsed = !this._record.collapsed;
  4583. this._scheduleRefresh(false);
  4584. },
  4585.  
  4586. dispose: function()
  4587. {
  4588. this.element.parentElement.removeChild(this.element);
  4589. this._expandElement._dispose();
  4590. }
  4591. }
  4592.  
  4593.  
  4594. WebInspector.TimelineExpandableElement = function(container)
  4595. {
  4596. this._element = document.createElement("div");
  4597. this._element.className = "timeline-expandable";
  4598.  
  4599. var leftBorder = document.createElement("div");
  4600. leftBorder.className = "timeline-expandable-left";
  4601. this._element.appendChild(leftBorder);
  4602.  
  4603. container.appendChild(this._element);
  4604. }
  4605.  
  4606. WebInspector.TimelineExpandableElement.prototype = {
  4607. _update: function(record, index, left, width)
  4608. {
  4609. const rowHeight = WebInspector.TimelinePanel.rowHeight;
  4610. if (record.visibleChildrenCount || record.invisibleChildrenCount) {
  4611. this._element.style.top = index * rowHeight + "px";
  4612. this._element.style.left = left + "px";
  4613. this._element.style.width = Math.max(12, width + 25) + "px";
  4614. if (!record.collapsed) {
  4615. this._element.style.height = (record.visibleChildrenCount + 1) * rowHeight + "px";
  4616. this._element.addStyleClass("timeline-expandable-expanded");
  4617. this._element.removeStyleClass("timeline-expandable-collapsed");
  4618. } else {
  4619. this._element.style.height = rowHeight + "px";
  4620. this._element.addStyleClass("timeline-expandable-collapsed");
  4621. this._element.removeStyleClass("timeline-expandable-expanded");
  4622. }
  4623. this._element.removeStyleClass("hidden");
  4624. } else
  4625. this._element.addStyleClass("hidden");
  4626. },
  4627.  
  4628. _dispose: function()
  4629. {
  4630. this._element.parentElement.removeChild(this._element);
  4631. }
  4632. }
  4633.  
  4634.  
  4635. WebInspector.TimelineCategoryFilter = function()
  4636. {
  4637. }
  4638.  
  4639. WebInspector.TimelineCategoryFilter.prototype = {
  4640.  
  4641. accept: function(record)
  4642. {
  4643. return !record.category.hidden && record.type !== WebInspector.TimelineModel.RecordType.BeginFrame;
  4644. }
  4645. }
  4646.  
  4647.  
  4648. WebInspector.TimelineIsLongFilter = function(panel)
  4649. {
  4650. this._panel = panel;
  4651. }
  4652.  
  4653. WebInspector.TimelineIsLongFilter.prototype = {
  4654.  
  4655. accept: function(record)
  4656. {
  4657. return this._panel._showShortEvents || record.isLong();
  4658. }
  4659. }
  4660.  
  4661.  
  4662. WebInspector.TimelineSearchFilter = function(regExp)
  4663. {
  4664. this._regExp = regExp;
  4665. }
  4666.  
  4667. WebInspector.TimelineSearchFilter.prototype = {
  4668.  
  4669.  
  4670. accept: function(record)
  4671. {
  4672. return WebInspector.TimelineRecordListRow.testContentMatching(record, this._regExp);
  4673. }
  4674. }
  4675.